From 574e529c1ce7d9e56b938044d8633c392a8cf37f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jelmer=20Vernoo=C4=B3?= Date: Wed, 10 May 2023 15:36:24 +0000 Subject: [PATCH 1/2] Run ruff fix --- Makefile | 3 + dulwich/archive.py | 6 +- dulwich/bundle.py | 5 +- dulwich/cli.py | 2 +- dulwich/client.py | 128 ++++++++++++------- dulwich/cloud/gcs.py | 7 +- dulwich/config.py | 35 ++++-- dulwich/contrib/diffstat.py | 5 +- dulwich/contrib/paramiko_vendor.py | 4 +- dulwich/contrib/requests_vendor.py | 10 +- dulwich/contrib/swift.py | 79 +++++++----- dulwich/contrib/test_paramiko_vendor.py | 4 +- dulwich/contrib/test_release_robot.py | 8 +- dulwich/contrib/test_swift.py | 6 +- dulwich/contrib/test_swift_smoke.py | 6 +- dulwich/credentials.py | 6 +- dulwich/diff_tree.py | 15 ++- dulwich/errors.py | 20 +-- dulwich/fastexport.py | 7 +- dulwich/file.py | 9 +- dulwich/graph.py | 9 +- dulwich/greenthreads.py | 9 +- dulwich/hooks.py | 28 ++--- dulwich/ignore.py | 13 +- dulwich/index.py | 43 +++++-- dulwich/lfs.py | 2 +- dulwich/line_ending.py | 28 ++--- dulwich/lru_cache.py | 7 +- dulwich/mailmap.py | 2 +- dulwich/object_store.py | 87 +++++++++---- dulwich/objects.py | 75 ++++++----- dulwich/objectspec.py | 2 +- dulwich/pack.py | 75 ++++++----- dulwich/patch.py | 3 +- dulwich/porcelain.py | 91 +++++++++----- dulwich/protocol.py | 11 +- dulwich/reflog.py | 3 +- dulwich/refs.py | 29 +++-- dulwich/repo.py | 154 +++++++++++++++-------- dulwich/server.py | 108 ++++++++++------ dulwich/stash.py | 4 +- dulwich/submodule.py | 5 +- dulwich/tests/__init__.py | 4 +- dulwich/tests/compat/server_utils.py | 2 +- dulwich/tests/compat/test_client.py | 12 +- dulwich/tests/compat/test_repository.py | 3 +- dulwich/tests/compat/test_web.py | 8 +- dulwich/tests/compat/utils.py | 3 +- dulwich/tests/test_client.py | 40 ++++-- dulwich/tests/test_config.py | 16 ++- dulwich/tests/test_credentials.py | 3 +- dulwich/tests/test_diff_tree.py | 24 +++- dulwich/tests/test_ignore.py | 11 +- dulwich/tests/test_index.py | 28 +++-- dulwich/tests/test_line_ending.py | 12 +- dulwich/tests/test_lru_cache.py | 2 +- dulwich/tests/test_missing_obj_finder.py | 4 +- dulwich/tests/test_object_store.py | 28 +++-- dulwich/tests/test_objects.py | 40 ++++-- dulwich/tests/test_objectspec.py | 13 +- dulwich/tests/test_pack.py | 43 +++++-- dulwich/tests/test_patch.py | 10 +- dulwich/tests/test_porcelain.py | 11 +- dulwich/tests/test_protocol.py | 19 ++- dulwich/tests/test_reflog.py | 8 +- dulwich/tests/test_refs.py | 16 ++- dulwich/tests/test_repository.py | 15 ++- dulwich/tests/test_server.py | 36 ++++-- dulwich/tests/test_walk.py | 7 +- dulwich/tests/test_web.py | 43 ++++--- dulwich/tests/utils.py | 15 ++- dulwich/walk.py | 16 ++- dulwich/web.py | 33 +++-- pyproject.toml | 15 +++ 74 files changed, 1072 insertions(+), 621 deletions(-) diff --git a/Makefile b/Makefile index 8bb618e49..9948240f5 100644 --- a/Makefile +++ b/Makefile @@ -75,3 +75,6 @@ coverage-html: coverage apidocs: pydoctor --intersphinx http://urllib3.readthedocs.org/en/latest/objects.inv --intersphinx http://docs.python.org/3/objects.inv --docformat=google dulwich --project-url=https://www.dulwich.io/ --project-name=dulwich + +fix: + ruff check --fix . diff --git a/dulwich/archive.py b/dulwich/archive.py index 5cf1bb323..fe74350b2 100644 --- a/dulwich/archive.py +++ b/dulwich/archive.py @@ -19,9 +19,7 @@ # License, Version 2.0. # -"""Generates tarballs for Git trees. - -""" +"""Generates tarballs for Git trees.""" import posixpath import stat @@ -43,7 +41,7 @@ class ChunkedBytesIO: list_of_bytestrings) """ - def __init__(self, contents): + def __init__(self, contents) -> None: self.contents = contents self.pos = (0, 0) diff --git a/dulwich/bundle.py b/dulwich/bundle.py index c7029ea47..3683feab1 100644 --- a/dulwich/bundle.py +++ b/dulwich/bundle.py @@ -18,8 +18,7 @@ # License, Version 2.0. # -"""Bundle format support. -""" +"""Bundle format support.""" from typing import Dict, List, Optional, Sequence, Tuple, Union @@ -35,7 +34,7 @@ class Bundle: references: Dict[str, bytes] = {} pack_data: Union[PackData, Sequence[bytes]] = [] - def __repr__(self): + def __repr__(self) -> str: return (f"<{type(self).__name__}(version={self.version}, " f"capabilities={self.capabilities}, " f"prerequisites={self.prerequisites}, " diff --git a/dulwich/cli.py b/dulwich/cli.py index 47ab4b14a..e183afc6f 100755 --- a/dulwich/cli.py +++ b/dulwich/cli.py @@ -21,7 +21,7 @@ # License, Version 2.0. # -"""Simple command-line interface to Dulwich> +"""Simple command-line interface to Dulwich>. This is a very simple command-line wrapper for Dulwich. It is by no means intended to be a full-blown Git command-line interface but just diff --git a/dulwich/client.py b/dulwich/client.py index 4e86146af..2fd77c858 100644 --- a/dulwich/client.py +++ b/dulwich/client.py @@ -46,8 +46,20 @@ import sys from contextlib import closing from io import BufferedReader, BytesIO -from typing import (IO, TYPE_CHECKING, Any, Callable, Dict, Iterable, Iterator, - List, Optional, Set, Tuple, Union) +from typing import ( + IO, + TYPE_CHECKING, + Any, + Callable, + Dict, + Iterable, + Iterator, + List, + Optional, + Set, + Tuple, + Union, +) from urllib.parse import quote as urlquote from urllib.parse import unquote as urlunquote from urllib.parse import urljoin, urlparse, urlunparse, urlunsplit @@ -59,23 +71,50 @@ from .config import Config, apply_instead_of, get_xdg_config_home_path from .errors import GitProtocolError, NotGitRepository, SendPackError -from .pack import (PACK_SPOOL_FILE_MAX_SIZE, PackChunkGenerator, - UnpackedObject, write_pack_from_container) -from .protocol import (_RBUFSIZE, CAPABILITIES_REF, CAPABILITY_AGENT, - CAPABILITY_DELETE_REFS, CAPABILITY_INCLUDE_TAG, - CAPABILITY_MULTI_ACK, CAPABILITY_MULTI_ACK_DETAILED, - CAPABILITY_OFS_DELTA, CAPABILITY_QUIET, - CAPABILITY_REPORT_STATUS, CAPABILITY_SHALLOW, - CAPABILITY_SIDE_BAND_64K, CAPABILITY_SYMREF, - CAPABILITY_THIN_PACK, COMMAND_DEEPEN, COMMAND_DONE, - COMMAND_HAVE, COMMAND_SHALLOW, COMMAND_UNSHALLOW, - COMMAND_WANT, KNOWN_RECEIVE_CAPABILITIES, - KNOWN_UPLOAD_CAPABILITIES, SIDE_BAND_CHANNEL_DATA, - SIDE_BAND_CHANNEL_FATAL, SIDE_BAND_CHANNEL_PROGRESS, - TCP_GIT_PORT, ZERO_SHA, HangupException, PktLineParser, - Protocol, agent_string, capability_agent, - extract_capabilities, extract_capability_names, - parse_capability, pkt_line) +from .pack import ( + PACK_SPOOL_FILE_MAX_SIZE, + PackChunkGenerator, + UnpackedObject, + write_pack_from_container, +) +from .protocol import ( + _RBUFSIZE, + CAPABILITIES_REF, + CAPABILITY_AGENT, + CAPABILITY_DELETE_REFS, + CAPABILITY_INCLUDE_TAG, + CAPABILITY_MULTI_ACK, + CAPABILITY_MULTI_ACK_DETAILED, + CAPABILITY_OFS_DELTA, + CAPABILITY_QUIET, + CAPABILITY_REPORT_STATUS, + CAPABILITY_SHALLOW, + CAPABILITY_SIDE_BAND_64K, + CAPABILITY_SYMREF, + CAPABILITY_THIN_PACK, + COMMAND_DEEPEN, + COMMAND_DONE, + COMMAND_HAVE, + COMMAND_SHALLOW, + COMMAND_UNSHALLOW, + COMMAND_WANT, + KNOWN_RECEIVE_CAPABILITIES, + KNOWN_UPLOAD_CAPABILITIES, + SIDE_BAND_CHANNEL_DATA, + SIDE_BAND_CHANNEL_FATAL, + SIDE_BAND_CHANNEL_PROGRESS, + TCP_GIT_PORT, + ZERO_SHA, + HangupException, + PktLineParser, + Protocol, + agent_string, + capability_agent, + extract_capabilities, + extract_capability_names, + parse_capability, + pkt_line, +) from .refs import PEELED_TAG_SUFFIX, _import_remote_refs, read_info_refs from .repo import Repo @@ -89,7 +128,7 @@ class InvalidWants(Exception): """Invalid wants.""" - def __init__(self, wants): + def __init__(self, wants) -> None: Exception.__init__( self, "requested wants not in server provided refs: %r" % wants ) @@ -98,7 +137,7 @@ def __init__(self, wants): class HTTPUnauthorized(Exception): """Raised when authentication fails.""" - def __init__(self, www_authenticate, url): + def __init__(self, www_authenticate, url) -> None: Exception.__init__(self, "No valid credentials provided") self.www_authenticate = www_authenticate self.url = url @@ -107,7 +146,7 @@ def __init__(self, www_authenticate, url): class HTTPProxyUnauthorized(Exception): """Raised when proxy authentication fails.""" - def __init__(self, proxy_authenticate, url): + def __init__(self, proxy_authenticate, url) -> None: Exception.__init__(self, "No valid proxy credentials provided") self.proxy_authenticate = proxy_authenticate self.url = url @@ -148,7 +187,7 @@ def _win32_peek_avail(handle): class ReportStatusParser: """Handle status as reported by servers with 'report-status' capability.""" - def __init__(self): + def __init__(self) -> None: self._done = False self._pack_status = None self._ref_statuses = [] @@ -241,7 +280,7 @@ class FetchPackResult: "viewvalues", ] - def __init__(self, refs, symrefs, agent, new_shallow=None, new_unshallow=None): + def __init__(self, refs, symrefs, agent, new_shallow=None, new_unshallow=None) -> None: self.refs = refs self.symrefs = symrefs self.agent = agent @@ -267,7 +306,7 @@ def __eq__(self, other): and self.agent == other.agent ) - def __contains__(self, name): + def __contains__(self, name) -> bool: self._warn_deprecated() return name in self.refs @@ -275,7 +314,7 @@ def __getitem__(self, name): self._warn_deprecated() return self.refs[name] - def __len__(self): + def __len__(self) -> int: self._warn_deprecated() return len(self.refs) @@ -289,7 +328,7 @@ def __getattribute__(self, name): return getattr(self.refs, name) return super().__getattribute__(name) - def __repr__(self): + def __repr__(self) -> str: return "{}({!r}, {!r}, {!r})".format( self.__class__.__name__, self.refs, @@ -325,7 +364,7 @@ class SendPackResult: "viewvalues", ] - def __init__(self, refs, agent=None, ref_status=None): + def __init__(self, refs, agent=None, ref_status=None) -> None: self.refs = refs self.agent = agent self.ref_status = ref_status @@ -345,7 +384,7 @@ def __eq__(self, other): return self.refs == other return self.refs == other.refs and self.agent == other.agent - def __contains__(self, name): + def __contains__(self, name) -> bool: self._warn_deprecated() return name in self.refs @@ -353,7 +392,7 @@ def __getitem__(self, name): self._warn_deprecated() return self.refs[name] - def __len__(self): + def __len__(self) -> int: self._warn_deprecated() return len(self.refs) @@ -367,7 +406,7 @@ def __getattribute__(self, name): return getattr(self.refs, name) return super().__getattribute__(name) - def __repr__(self): + def __repr__(self) -> str: return "{}({!r}, {!r})".format(self.__class__.__name__, self.refs, self.agent) @@ -387,7 +426,7 @@ def _read_shallow_updates(pkt_seq): class _v1ReceivePackHeader: - def __init__(self, capabilities, old_refs, new_refs): + def __init__(self, capabilities, old_refs, new_refs) -> None: self.want = [] self.have = [] self._it = self._handle_receive_pack_head(capabilities, old_refs, new_refs) @@ -596,7 +635,7 @@ def __init__( report_activity=None, quiet=False, include_tags=False, - ): + ) -> None: """Create a new GitClient instance. Args: @@ -924,8 +963,7 @@ def archive( subdirs=None, prefix=None, ): - """Retrieve an archive of the specified tree. - """ + """Retrieve an archive of the specified tree.""" raise NotImplementedError(self.archive) @@ -961,7 +999,7 @@ class TraditionalGitClient(GitClient): DEFAULT_ENCODING = "utf-8" - def __init__(self, path_encoding=DEFAULT_ENCODING, **kwargs): + def __init__(self, path_encoding=DEFAULT_ENCODING, **kwargs) -> None: self._remote_path_encoding = path_encoding super().__init__(**kwargs) @@ -1203,7 +1241,7 @@ def archive( class TCPGitClient(TraditionalGitClient): """A Git Client that works over TCP directly (i.e. git://).""" - def __init__(self, host, port=None, **kwargs): + def __init__(self, host, port=None, **kwargs) -> None: if port is None: port = TCP_GIT_PORT self._host = host @@ -1269,7 +1307,7 @@ def close(): class SubprocessWrapper: """A socket-like object that talks to a subprocess via pipes.""" - def __init__(self, proc): + def __init__(self, proc) -> None: self.proc = proc self.read = BufferedReader(proc.stdout).read self.write = proc.stdin.write @@ -1350,7 +1388,7 @@ class LocalGitClient(GitClient): """Git Client that just uses a local Repo.""" def __init__(self, thin_packs=True, report_activity=None, - config: Optional[Config] = None): + config: Optional[Config] = None) -> None: """Create a new LocalGitClient instance. Args: @@ -1503,7 +1541,6 @@ def fetch_pack( def get_refs(self, path): """Retrieve the current refs from a git smart server.""" - with self._open_repo(path) as target: return target.get_refs() @@ -1548,7 +1585,7 @@ def run_command( class StrangeHostname(Exception): """Refusing to connect to strange SSH hostname.""" - def __init__(self, hostname): + def __init__(self, hostname) -> None: super().__init__(hostname) @@ -1682,7 +1719,7 @@ def __init__( key_filename=None, ssh_command=None, **kwargs - ): + ) -> None: self.host = host self.port = port self.username = username @@ -1907,7 +1944,7 @@ class AbstractHttpGitClient(GitClient): _http_request method. """ - def __init__(self, base_url, dumb=False, **kwargs): + def __init__(self, base_url, dumb=False, **kwargs) -> None: self._base_url = base_url.rstrip("/") + "/" self.dumb = dumb GitClient.__init__(self, **kwargs) @@ -1927,7 +1964,6 @@ def _http_request(self, url, headers=None, data=None): method for the response data. """ - raise NotImplementedError(self._http_request) def _discover_references(self, service, base_url): @@ -2150,7 +2186,7 @@ def from_parsedurl(cls, parsedurl, **kwargs): kwargs["username"] = urlunquote(username) return cls(urlunparse(parsedurl), **kwargs) - def __repr__(self): + def __repr__(self) -> str: return "{}({!r}, dumb={!r})".format( type(self).__name__, self._base_url, @@ -2168,7 +2204,7 @@ def __init__( username=None, password=None, **kwargs - ): + ) -> None: self._username = username self._password = password diff --git a/dulwich/cloud/gcs.py b/dulwich/cloud/gcs.py index cc60d9cf5..8c9367238 100644 --- a/dulwich/cloud/gcs.py +++ b/dulwich/cloud/gcs.py @@ -25,20 +25,19 @@ import tempfile from ..object_store import BucketBasedObjectStore -from ..pack import (PACK_SPOOL_FILE_MAX_SIZE, Pack, PackData, - load_pack_index_file) +from ..pack import PACK_SPOOL_FILE_MAX_SIZE, Pack, PackData, load_pack_index_file # TODO(jelmer): For performance, read ranges? class GcsObjectStore(BucketBasedObjectStore): - def __init__(self, bucket, subpath=''): + def __init__(self, bucket, subpath='') -> None: super().__init__() self.bucket = bucket self.subpath = subpath - def __repr__(self): + def __repr__(self) -> str: return "{}({!r}, subpath={!r})".format( type(self).__name__, self.bucket, self.subpath) diff --git a/dulwich/config.py b/dulwich/config.py index 974239dbc..dd04dc9c5 100644 --- a/dulwich/config.py +++ b/dulwich/config.py @@ -20,7 +20,7 @@ """Reading and writing Git configuration files. -TODO: +Todo: * preserve formatting when updating configuration files * treat subsection names as case-insensitive for [branch.foo] style subsections @@ -29,8 +29,18 @@ import os import sys from contextlib import suppress -from typing import (BinaryIO, Iterable, Iterator, KeysView, List, - MutableMapping, Optional, Tuple, Union, overload) +from typing import ( + BinaryIO, + Iterable, + Iterator, + KeysView, + List, + MutableMapping, + Optional, + Tuple, + Union, + overload, +) from .file import GitFile @@ -49,7 +59,7 @@ def lower_key(key): class CaseInsensitiveOrderedMultiDict(MutableMapping): - def __init__(self): + def __init__(self) -> None: self._real = [] self._keyed = {} @@ -72,7 +82,7 @@ def make(cls, dict_in=None): return out - def __len__(self): + def __len__(self) -> int: return len(self._keyed) def keys(self) -> KeysView[Tuple[bytes, ...]]: @@ -87,11 +97,11 @@ def __iter__(self): def values(self): return self._keyed.values() - def __setitem__(self, key, value): + def __setitem__(self, key, value) -> None: self._real.append((key, value)) self._keyed[lower_key(key)] = value - def __delitem__(self, key): + def __delitem__(self, key) -> None: key = lower_key(key) del self._keyed[key] for i, (actual, unused_value) in reversed(list(enumerate(self._real))): @@ -181,6 +191,7 @@ def get_boolean( section: Tuple with section name and optional subsection name name: Name of the setting, including section and possible subsection. + Returns: Contents of the setting """ @@ -670,7 +681,7 @@ class StackedConfig(Config): def __init__( self, backends: List[ConfigFile], writable: Optional[ConfigFile] = None - ): + ) -> None: self.backends = backends self.writable = writable @@ -744,7 +755,7 @@ def sections(self) -> Iterator[Section]: def read_submodules(path: str) -> Iterator[Tuple[bytes, bytes, bytes]]: - """read a .gitmodules file.""" + """Read a .gitmodules file.""" cfg = ConfigFile.from_path(path) return parse_submodules(cfg) @@ -767,8 +778,7 @@ def parse_submodules(config: ConfigFile) -> Iterator[Tuple[bytes, bytes, bytes]] def iter_instead_of(config: Config, push: bool = False) -> Iterable[Tuple[str, str]]: - """Iterate over insteadOf / pushInsteadOf values. - """ + """Iterate over insteadOf / pushInsteadOf values.""" for section in config.sections(): if section[0] != b'url': continue @@ -788,8 +798,7 @@ def iter_instead_of(config: Config, push: bool = False) -> Iterable[Tuple[str, s def apply_instead_of(config: Config, orig_url: str, push: bool = False) -> str: - """Apply insteadOf / pushInsteadOf to a URL. - """ + """Apply insteadOf / pushInsteadOf to a URL.""" longest_needle = "" updated_url = orig_url for needle, replacement in iter_instead_of(config, push): diff --git a/dulwich/contrib/diffstat.py b/dulwich/contrib/diffstat.py index 5c9bfc3fa..563b5982e 100755 --- a/dulwich/contrib/diffstat.py +++ b/dulwich/contrib/diffstat.py @@ -110,13 +110,14 @@ def _parse_patch(lines: List[bytes]) -> Tuple[List[bytes], List[bool], List[Tupl # may not be encodable even to utf-8 def diffstat(lines, max_width=80): """Generate summary statistics from a git style diff ala - (git diff tag1 tag2 --stat) + (git diff tag1 tag2 --stat). + Args: lines: list of byte string "lines" from the diff to be parsed max_width: maximum line length for generating the summary statistics (default 80) Returns: A byte string that lists the changed files with change - counts and histogram + counts and histogram. """ names, nametypes, counts = _parse_patch(lines) insert = [] diff --git a/dulwich/contrib/paramiko_vendor.py b/dulwich/contrib/paramiko_vendor.py index d5b83939f..7008a819e 100644 --- a/dulwich/contrib/paramiko_vendor.py +++ b/dulwich/contrib/paramiko_vendor.py @@ -35,7 +35,7 @@ class _ParamikoWrapper: - def __init__(self, client, channel): + def __init__(self, client, channel) -> None: self.client = client self.channel = channel @@ -73,7 +73,7 @@ def close(self): class ParamikoSSHVendor: # http://docs.paramiko.org/en/2.4/api/client.html - def __init__(self, **kwargs): + def __init__(self, **kwargs) -> None: self.kwargs = kwargs def run_command( diff --git a/dulwich/contrib/requests_vendor.py b/dulwich/contrib/requests_vendor.py index db937a57e..8bd437406 100644 --- a/dulwich/contrib/requests_vendor.py +++ b/dulwich/contrib/requests_vendor.py @@ -33,8 +33,12 @@ from requests import Session -from ..client import (AbstractHttpGitClient, HTTPProxyUnauthorized, - HTTPUnauthorized, default_user_agent_string) +from ..client import ( + AbstractHttpGitClient, + HTTPProxyUnauthorized, + HTTPUnauthorized, + default_user_agent_string, +) from ..errors import GitProtocolError, NotGitRepository @@ -47,7 +51,7 @@ def __init__( username=None, password=None, **kwargs - ): + ) -> None: self._username = username self._password = password diff --git a/dulwich/contrib/swift.py b/dulwich/contrib/swift.py index 263a14f3a..0b7c8d6b3 100644 --- a/dulwich/contrib/swift.py +++ b/dulwich/contrib/swift.py @@ -43,10 +43,21 @@ from ..lru_cache import LRUSizeCache from ..object_store import INFODIR, PACKDIR, PackBasedObjectStore from ..objects import S_ISGITLINK, Blob, Commit, Tag, Tree -from ..pack import (Pack, PackData, PackIndexer, PackStreamCopier, - _compute_object_size, compute_file_sha, iter_sha1, - load_pack_index_file, read_pack_header, unpack_object, - write_pack_header, write_pack_index_v2, write_pack_object) +from ..pack import ( + Pack, + PackData, + PackIndexer, + PackStreamCopier, + _compute_object_size, + compute_file_sha, + iter_sha1, + load_pack_index_file, + read_pack_header, + unpack_object, + write_pack_header, + write_pack_index_v2, + write_pack_object, +) from ..protocol import TCP_GIT_PORT from ..refs import InfoRefsContainer, read_info_refs, write_info_refs from ..repo import OBJECTDIR, BaseRepo @@ -104,7 +115,7 @@ def next(self): def load_conf(path=None, file=None): - """Load configuration in global var CONF + """Load configuration in global var CONF. Args: path: The path to the configuration file @@ -134,7 +145,7 @@ def load_conf(path=None, file=None): def swift_load_pack_index(scon, filename): - """Read a pack index file from Swift + """Read a pack index file from Swift. Args: scon: a `SwiftConnector` instance @@ -187,10 +198,10 @@ class SwiftException(Exception): class SwiftConnector: - """A Connector to swift that manage authentication and errors catching""" + """A Connector to swift that manage authentication and errors catching.""" - def __init__(self, root, conf): - """Initialize a SwiftConnector + def __init__(self, root, conf) -> None: + """Initialize a SwiftConnector. Args: root: The swift container that will act as Git bare repository @@ -301,7 +312,7 @@ def swift_auth_v2(self): return endpoint[self.endpoint_type], token def test_root_exists(self): - """Check that Swift container exist + """Check that Swift container exist. Returns: True if exist or None it not """ @@ -315,7 +326,7 @@ def test_root_exists(self): return True def create_root(self): - """Create the Swift container + """Create the Swift container. Raises: SwiftException: if unable to create @@ -328,7 +339,7 @@ def create_root(self): ) def get_container_objects(self): - """Retrieve objects list in a container + """Retrieve objects list in a container. Returns: A list of dict that describe objects or None if container does not exist @@ -346,7 +357,7 @@ def get_container_objects(self): return json.loads(content) def get_object_stat(self, name): - """Retrieve object stat + """Retrieve object stat. Args: name: The object name @@ -367,7 +378,7 @@ def get_object_stat(self, name): return resp_headers def put_object(self, name, content): - """Put an object + """Put an object. Args: name: The object name @@ -397,7 +408,7 @@ def _send(): ) def get_object(self, name, range=None): - """Retrieve an object + """Retrieve an object. Args: name: The object name @@ -424,7 +435,7 @@ def get_object(self, name, range=None): return BytesIO(content) def del_object(self, name): - """Delete an object + """Delete an object. Args: name: The object name @@ -439,7 +450,7 @@ def del_object(self, name): ) def del_root(self): - """Delete the root container by removing container content + """Delete the root container by removing container content. Raises: SwiftException: if unable to delete @@ -454,7 +465,7 @@ def del_root(self): class SwiftPackReader: - """A SwiftPackReader that mimic read and sync method + """A SwiftPackReader that mimic read and sync method. The reader allows to read a specified amount of bytes from a given offset of a Swift object. A read offset is kept internally. @@ -463,8 +474,8 @@ class SwiftPackReader: to read from Swift. """ - def __init__(self, scon, filename, pack_length): - """Initialize a SwiftPackReader + def __init__(self, scon, filename, pack_length) -> None: + """Initialize a SwiftPackReader. Args: scon: a `SwiftConnector` instance @@ -488,7 +499,7 @@ def _read(self, more=False): self.buff = ret def read(self, length): - """Read a specified amount of Bytes form the pack object + """Read a specified amount of Bytes form the pack object. Args: length: amount of bytes to read @@ -509,7 +520,7 @@ def read(self, length): return data def seek(self, offset): - """Seek to a specified offset + """Seek to a specified offset. Args: offset: the offset to seek to @@ -519,7 +530,7 @@ def seek(self, offset): self.offset = 0 def read_checksum(self): - """Read the checksum from the pack + """Read the checksum from the pack. Returns: the checksum bytestring """ @@ -533,8 +544,8 @@ class SwiftPackData(PackData): using the Range header feature of Swift. """ - def __init__(self, scon, filename): - """Initialize a SwiftPackReader + def __init__(self, scon, filename) -> None: + """Initialize a SwiftPackReader. Args: scon: a `SwiftConnector` instance @@ -578,7 +589,7 @@ class SwiftPack(Pack): PackData. """ - def __init__(self, *args, **kwargs): + def __init__(self, *args, **kwargs) -> None: self.scon = kwargs["scon"] del kwargs["scon"] super().__init__(*args, **kwargs) @@ -597,13 +608,13 @@ def pack_info(self): class SwiftObjectStore(PackBasedObjectStore): - """A Swift Object Store + """A Swift Object Store. Allow to manage a bare Git repository from Openstack Swift. This object store only supports pack files and not loose objects. """ - def __init__(self, scon): + def __init__(self, scon) -> None: """Open a Swift object store. Args: @@ -630,7 +641,7 @@ def _update_pack_cache(self): return ret def _iter_loose_objects(self): - """Loose objects are not supported by this repository""" + """Loose objects are not supported by this repository.""" return [] def pack_info_get(self, sha): @@ -712,7 +723,7 @@ def _get_loose_object(self, sha): return None def add_thin_pack(self, read_all, read_some): - """Read a thin pack + """Read a thin pack. Read it from a stream and complete it in a temporary file. Then the pack and the corresponding index file are uploaded to Swift. @@ -792,7 +803,7 @@ def _complete_thin_pack(self, f, path, copier, indexer): class SwiftInfoRefsContainer(InfoRefsContainer): """Manage references in info/refs object.""" - def __init__(self, scon, store): + def __init__(self, scon, store) -> None: self.scon = scon self.filename = "info/refs" self.store = store @@ -850,7 +861,7 @@ def allkeys(self): class SwiftRepo(BaseRepo): - def __init__(self, root, conf): + def __init__(self, root, conf) -> None: """Init a Git bare Repository on top of a Swift container. References are managed in info/refs objects by @@ -884,7 +895,7 @@ def _determine_file_mode(self): return False def _put_named_file(self, filename, contents): - """Put an object in a Swift container + """Put an object in a Swift container. Args: filename: the path to the object to put on Swift @@ -916,7 +927,7 @@ def init_bare(cls, scon, conf): class SwiftSystemBackend(Backend): - def __init__(self, logger, conf): + def __init__(self, logger, conf) -> None: self.conf = conf self.logger = logger diff --git a/dulwich/contrib/test_paramiko_vendor.py b/dulwich/contrib/test_paramiko_vendor.py index 9f5b21cd2..b7e582879 100644 --- a/dulwich/contrib/test_paramiko_vendor.py +++ b/dulwich/contrib/test_paramiko_vendor.py @@ -35,8 +35,8 @@ from .paramiko_vendor import ParamikoSSHVendor class Server(paramiko.ServerInterface): - """http://docs.paramiko.org/en/2.4/api/server.html""" - def __init__(self, commands, *args, **kwargs): + """http://docs.paramiko.org/en/2.4/api/server.html.""" + def __init__(self, commands, *args, **kwargs) -> None: super().__init__(*args, **kwargs) self.commands = commands diff --git a/dulwich/contrib/test_release_robot.py b/dulwich/contrib/test_release_robot.py index bff588287..e37cd6c97 100644 --- a/dulwich/contrib/test_release_robot.py +++ b/dulwich/contrib/test_release_robot.py @@ -40,10 +40,10 @@ def gmtime_to_datetime(gmt): class TagPatternTests(unittest.TestCase): - """test tag patterns""" + """test tag patterns.""" def test_tag_pattern(self): - """test tag patterns""" + """Test tag patterns.""" test_cases = { "0.3": "0.3", "v0.3": "0.3", @@ -63,7 +63,7 @@ def test_tag_pattern(self): class GetRecentTagsTest(unittest.TestCase): - """test get recent tags""" + """test get recent tags.""" # Git repo for dulwich project test_repo = os.path.join(BASEDIR, "dulwich_test_repo.zip") @@ -116,7 +116,7 @@ def tearDownClass(cls): shutil.rmtree(cls.projdir) def test_get_recent_tags(self): - """test get recent tags""" + """Test get recent tags.""" tags = release_robot.get_recent_tags(self.projdir) # get test tags for tag, metadata in tags: tag = tag.encode("utf-8") diff --git a/dulwich/contrib/test_swift.py b/dulwich/contrib/test_swift.py index afb1b5c76..9314542b4 100644 --- a/dulwich/contrib/test_swift.py +++ b/dulwich/contrib/test_swift.py @@ -88,7 +88,7 @@ def create_swift_connector(store={}): class Response: - def __init__(self, headers={}, status=200, content=None): + def __init__(self, headers={}, status=200, content=None) -> None: self.headers = headers self.status_code = status self.content = content @@ -179,7 +179,7 @@ def create_commits(length=1, marker=b"Default"): @skipIf(missing_libs, skipmsg) class FakeSwiftConnector: - def __init__(self, root, conf, store=None): + def __init__(self, root, conf, store=None) -> None: if store: self.store = store else: @@ -301,7 +301,7 @@ def setUp(self): self.object_store = {} def test_init(self): - """info/refs does not exists""" + """info/refs does not exists.""" irc = swift.SwiftInfoRefsContainer(self.fsc, self.object_store) self.assertEqual(len(irc._refs), 0) self.fsc.store = self.store diff --git a/dulwich/contrib/test_swift_smoke.py b/dulwich/contrib/test_swift_smoke.py index 2d2ca91c6..3c520c62c 100644 --- a/dulwich/contrib/test_swift_smoke.py +++ b/dulwich/contrib/test_swift_smoke.py @@ -20,7 +20,7 @@ # License, Version 2.0. # -"""Start functional tests +"""Start functional tests. A Swift installation must be available before starting those tests. The account and authentication method used @@ -48,9 +48,9 @@ class DulwichServer: - """Start the TCPGitServer with Swift backend""" + """Start the TCPGitServer with Swift backend.""" - def __init__(self, backend, port): + def __init__(self, backend, port) -> None: self.port = port self.backend = backend diff --git a/dulwich/credentials.py b/dulwich/credentials.py index ca7698af3..960f812e1 100644 --- a/dulwich/credentials.py +++ b/dulwich/credentials.py @@ -19,7 +19,7 @@ # License, Version 2.0. # -"""Support for git credential helpers +"""Support for git credential helpers. https://git-scm.com/book/en/v2/Git-Tools-Credential-Storage @@ -43,7 +43,7 @@ def match_urls(url: ParseResult, url_prefix: ParseResult) -> bool: def match_partial_url(valid_url: ParseResult, partial_url: str) -> bool: - """matches a parsed url with a partial url (no scheme/netloc)""" + """Matches a parsed url with a partial url (no scheme/netloc).""" if "://" not in partial_url: parsed = urlparse("scheme://" + partial_url) else: @@ -67,7 +67,7 @@ def match_partial_url(valid_url: ParseResult, partial_url: str) -> bool: def urlmatch_credential_sections( config: ConfigDict, url: Optional[str] ) -> Iterator[SectionLike]: - """Returns credential sections from the config which match the given URL""" + """Returns credential sections from the config which match the given URL.""" encoding = config.encoding or sys.getdefaultencoding() parsed_url = urlparse(url or "") for config_section in config.sections(): diff --git a/dulwich/diff_tree.py b/dulwich/diff_tree.py index a182fae3a..dc8e1bb38 100644 --- a/dulwich/diff_tree.py +++ b/dulwich/diff_tree.py @@ -74,6 +74,7 @@ def _merge_entries(path, tree1, tree2): path: A path to prepend to all tree entry names. tree1: The first Tree object to iterate, or None. tree2: The second Tree object to iterate, or None. + Returns: A list of pairs of TreeEntry objects for each pair of entries in the trees. If an entry exists in one tree but not the other, the other @@ -124,6 +125,7 @@ def walk_trees(store, tree1_id, tree2_id, prune_identical=False): tree1_id: The SHA of the first Tree object to iterate, or None. tree2_id: The SHA of the second Tree object to iterate, or None. prune_identical: If True, identical subtrees will not be walked. + Returns: Iterator over Pairs of TreeEntry objects for each pair of entries in the trees and their subtrees recursively. If an entry exists in one @@ -177,6 +179,7 @@ def tree_changes( rename_detector: RenameDetector object for detecting renames. change_type_same: Whether to report change types in the same entry or as delete+add. + Returns: Iterator over TreeChange instances for each change between the source and target tree. @@ -304,6 +307,7 @@ def _count_blocks(obj): Args: obj: The object to count blocks for. + Returns: A dict of block hashcode -> total bytes occurring. """ @@ -339,6 +343,7 @@ def _common_bytes(blocks1, blocks2): Args: blocks1: The first dict of block hashcode -> total bytes. blocks2: The second dict of block hashcode -> total bytes. + Returns: The number of bytes in common between blocks1 and blocks2. This is only approximate due to possible hash collisions. @@ -362,6 +367,7 @@ def _similarity_score(obj1, obj2, block_cache=None): obj2: The second object to score. block_cache: An optional dict of SHA to block counts to cache results between calls. + Returns: The similarity score between the two objects, defined as the number of bytes in common between the two objects divided by the @@ -402,7 +408,7 @@ def __init__( max_files=MAX_FILES, rewrite_threshold=REWRITE_THRESHOLD, find_copies_harder=False, - ): + ) -> None: """Initialize the rename detector. Args: @@ -631,7 +637,10 @@ def changes_with_renames( _count_blocks_py = _count_blocks try: # Try to import C versions - from dulwich._diff_tree import (_count_blocks, _is_tree, # type: ignore - _merge_entries) + from dulwich._diff_tree import ( # type: ignore + _count_blocks, + _is_tree, + _merge_entries, + ) except ImportError: pass diff --git a/dulwich/errors.py b/dulwich/errors.py index a4629b53c..03e65984f 100644 --- a/dulwich/errors.py +++ b/dulwich/errors.py @@ -32,7 +32,7 @@ class ChecksumMismatch(Exception): """A checksum didn't match the expected contents.""" - def __init__(self, expected, got, extra=None): + def __init__(self, expected, got, extra=None) -> None: if len(expected) == 20: expected = binascii.hexlify(expected) if len(got) == 20: @@ -63,7 +63,7 @@ class WrongObjectException(Exception): type_name: str - def __init__(self, sha, *args, **kwargs): + def __init__(self, sha, *args, **kwargs) -> None: Exception.__init__(self, "{} is not a {}".format(sha, self.type_name)) @@ -92,9 +92,9 @@ class NotBlobError(WrongObjectException): class MissingCommitError(Exception): - """Indicates that a commit was not found in the repository""" + """Indicates that a commit was not found in the repository.""" - def __init__(self, sha, *args, **kwargs): + def __init__(self, sha, *args, **kwargs) -> None: self.sha = sha Exception.__init__(self, "%s is not in the revision store" % sha) @@ -102,28 +102,28 @@ def __init__(self, sha, *args, **kwargs): class ObjectMissing(Exception): """Indicates that a requested object is missing.""" - def __init__(self, sha, *args, **kwargs): + def __init__(self, sha, *args, **kwargs) -> None: Exception.__init__(self, "%s is not in the pack" % sha) class ApplyDeltaError(Exception): """Indicates that applying a delta failed.""" - def __init__(self, *args, **kwargs): + def __init__(self, *args, **kwargs) -> None: Exception.__init__(self, *args, **kwargs) class NotGitRepository(Exception): """Indicates that no Git repository was found.""" - def __init__(self, *args, **kwargs): + def __init__(self, *args, **kwargs) -> None: Exception.__init__(self, *args, **kwargs) class GitProtocolError(Exception): """Git protocol exception.""" - def __init__(self, *args, **kwargs): + def __init__(self, *args, **kwargs) -> None: Exception.__init__(self, *args, **kwargs) def __eq__(self, other): @@ -137,7 +137,7 @@ class SendPackError(GitProtocolError): class HangupException(GitProtocolError): """Hangup exception.""" - def __init__(self, stderr_lines=None): + def __init__(self, stderr_lines=None) -> None: if stderr_lines: super().__init__( "\n".join( @@ -157,7 +157,7 @@ def __eq__(self, other): class UnexpectedCommandError(GitProtocolError): """Unexpected command received in a proto line.""" - def __init__(self, command): + def __init__(self, command) -> None: if command is None: command = "flush-pkt" else: diff --git a/dulwich/fastexport.py b/dulwich/fastexport.py index 335a0b8be..0c30e2f86 100644 --- a/dulwich/fastexport.py +++ b/dulwich/fastexport.py @@ -23,9 +23,8 @@ import stat -from fastimport import commands +from fastimport import commands, parser, processor from fastimport import errors as fastimport_errors -from fastimport import parser, processor from .index import commit_tree from .object_store import iter_tree_contents @@ -40,7 +39,7 @@ def split_email(text): class GitFastExporter: """Generate a fast-export output stream for Git objects.""" - def __init__(self, outf, store): + def __init__(self, outf, store) -> None: self.outf = outf self.store = store self.markers = {} @@ -122,7 +121,7 @@ class GitImportProcessor(processor.ImportProcessor): # FIXME: Batch creation of objects? - def __init__(self, repo, params=None, verbose=False, outf=None): + def __init__(self, repo, params=None, verbose=False, outf=None) -> None: processor.ImportProcessor.__init__(self, params, verbose) self.repo = repo self.last_commit = ZERO_SHA diff --git a/dulwich/file.py b/dulwich/file.py index 110605427..d15644714 100644 --- a/dulwich/file.py +++ b/dulwich/file.py @@ -34,7 +34,7 @@ def ensure_dir_exists(dirname): def _fancy_rename(oldname, newname): - """Rename file with temporary backup file to rollback if rename fails""" + """Rename file with temporary backup file to rollback if rename fails.""" if not os.path.exists(newname): try: os.rename(oldname, newname) @@ -97,7 +97,7 @@ def GitFile(filename, mode="rb", bufsize=-1, mask=0o644): class FileLocked(Exception): """File is already locked.""" - def __init__(self, filename, lockfilename): + def __init__(self, filename, lockfilename) -> None: self.filename = filename self.lockfilename = lockfilename super().__init__(filename, lockfilename) @@ -138,7 +138,7 @@ class _GitFile: "writelines", ) - def __init__(self, filename, mode, bufsize, mask): + def __init__(self, filename, mode, bufsize, mask) -> None: self._filename = filename if isinstance(self._filename, bytes): self._lockfilename = self._filename + b".lock" @@ -180,6 +180,7 @@ def close(self): However, it is not guaranteed to do so (e.g. if a filesystem becomes suddenly read-only), which will prevent future writes to this file until the lockfile is removed manually. + Raises: OSError: if the original file could not be overwritten. The lock file is still closed, so further attempts to write to the same @@ -203,7 +204,7 @@ def close(self): finally: self.abort() - def __del__(self): + def __del__(self) -> None: if not getattr(self, '_closed', True): warnings.warn('unclosed %r' % self, ResourceWarning, stacklevel=2) self.abort() diff --git a/dulwich/graph.py b/dulwich/graph.py index 1fcbcd6f6..ace895591 100644 --- a/dulwich/graph.py +++ b/dulwich/graph.py @@ -18,9 +18,7 @@ # and for a copy of the Apache # License, Version 2.0. -""" -Implementation of merge-base following the approach of git -""" +"""Implementation of merge-base following the approach of git.""" from collections import deque from typing import Deque @@ -83,7 +81,7 @@ def _has_candidates(wlst, cstates): def find_merge_base(repo, commit_ids): - """Find lowest common ancestors of commit_ids[0] and *any* of commits_ids[1:] + """Find lowest common ancestors of commit_ids[0] and *any* of commits_ids[1:]. Args: repo: Repository object @@ -104,7 +102,7 @@ def find_merge_base(repo, commit_ids): def find_octopus_base(repo, commit_ids): - """Find lowest common ancestors of *all* provided commit_ids + """Find lowest common ancestors of *all* provided commit_ids. Args: repo: Repository @@ -112,7 +110,6 @@ def find_octopus_base(repo, commit_ids): Returns: list of lowest common ancestor commit_ids """ - if not commit_ids: return [] if len(commit_ids) <= 2: diff --git a/dulwich/greenthreads.py b/dulwich/greenthreads.py index 12a304867..6593defee 100644 --- a/dulwich/greenthreads.py +++ b/dulwich/greenthreads.py @@ -25,8 +25,11 @@ import gevent from gevent import pool -from .object_store import (MissingObjectFinder, _collect_ancestors, - _collect_filetree_revs) +from .object_store import ( + MissingObjectFinder, + _collect_ancestors, + _collect_filetree_revs, +) from .objects import Commit, Tag @@ -75,7 +78,7 @@ def __init__( get_tagged=None, concurrency=1, get_parents=None, - ): + ) -> None: def collect_tree_sha(sha): self.sha_done.add(sha) cmt = object_store[sha] diff --git a/dulwich/hooks.py b/dulwich/hooks.py index 9f00e5069..0d813ab98 100644 --- a/dulwich/hooks.py +++ b/dulwich/hooks.py @@ -30,7 +30,7 @@ class Hook: """Generic hook object.""" def execute(self, *args): - """Execute the hook with the given args + """Execute the hook with the given args. Args: args: argument list to hook @@ -43,7 +43,7 @@ def execute(self, *args): class ShellHook(Hook): - """Hook by executable file + """Hook by executable file. Implements standard githooks(5) [0]: @@ -58,8 +58,8 @@ def __init__( pre_exec_callback=None, post_exec_callback=None, cwd=None, - ): - """Setup shell hook definition + ) -> None: + """Setup shell hook definition. Args: name: name of hook for error messages @@ -85,8 +85,7 @@ def __init__( self.cwd = cwd def execute(self, *args): - """Execute the hook with given args""" - + """Execute the hook with given args.""" if len(args) != self.numparam: raise HookError( "Hook %s executed with wrong number of args. \ @@ -115,28 +114,27 @@ def execute(self, *args): class PreCommitShellHook(ShellHook): - """pre-commit shell hook""" + """pre-commit shell hook.""" - def __init__(self, cwd, controldir): + def __init__(self, cwd, controldir) -> None: filepath = os.path.join(controldir, "hooks", "pre-commit") ShellHook.__init__(self, "pre-commit", filepath, 0, cwd=cwd) class PostCommitShellHook(ShellHook): - """post-commit shell hook""" + """post-commit shell hook.""" - def __init__(self, controldir): + def __init__(self, controldir) -> None: filepath = os.path.join(controldir, "hooks", "post-commit") ShellHook.__init__(self, "post-commit", filepath, 0, cwd=controldir) class CommitMsgShellHook(ShellHook): - """commit-msg shell hook - """ + """commit-msg shell hook.""" - def __init__(self, controldir): + def __init__(self, controldir) -> None: filepath = os.path.join(controldir, "hooks", "commit-msg") def prepare_msg(*args): @@ -163,9 +161,9 @@ def clean_msg(success, *args): class PostReceiveShellHook(ShellHook): - """post-receive shell hook""" + """post-receive shell hook.""" - def __init__(self, controldir): + def __init__(self, controldir) -> None: self.controldir = controldir filepath = os.path.join(controldir, "hooks", "post-receive") ShellHook.__init__(self, "post-receive", path=filepath, numparam=0) diff --git a/dulwich/ignore.py b/dulwich/ignore.py index 352b2e64a..d53bd3ca6 100644 --- a/dulwich/ignore.py +++ b/dulwich/ignore.py @@ -25,8 +25,7 @@ import os.path import re from contextlib import suppress -from typing import (TYPE_CHECKING, BinaryIO, Dict, Iterable, List, Optional, - Union) +from typing import TYPE_CHECKING, BinaryIO, Dict, Iterable, List, Optional, Union if TYPE_CHECKING: from .repo import Repo @@ -80,7 +79,6 @@ def translate(pat: bytes) -> bytes: Originally copied from fnmatch in Python 2.7, but modified for Dulwich to cope with features in Git ignore patterns. """ - res = b"(?ms)" if b"/" not in pat[:-1]: @@ -115,7 +113,6 @@ def read_ignore_patterns(f: BinaryIO) -> Iterable[bytes]: f: File-like object to read from Returns: List of patterns """ - for line in f: line = line.rstrip(b"\r\n") @@ -151,7 +148,7 @@ def match_pattern(path: bytes, pattern: bytes, ignorecase: bool = False) -> bool class Pattern: """A single ignore pattern.""" - def __init__(self, pattern: bytes, ignorecase: bool = False): + def __init__(self, pattern: bytes, ignorecase: bool = False) -> None: self.pattern = pattern self.ignorecase = ignorecase if pattern[0:1] == b"!": @@ -197,7 +194,7 @@ def match(self, path: bytes) -> bool: class IgnoreFilter: - def __init__(self, patterns: Iterable[bytes], ignorecase: bool = False, path=None): + def __init__(self, patterns: Iterable[bytes], ignorecase: bool = False, path=None) -> None: self._patterns: List[Pattern] = [] self._ignorecase = ignorecase self._path = path @@ -251,7 +248,7 @@ def __repr__(self) -> str: class IgnoreFilterStack: """Check for ignore status in multiple filters.""" - def __init__(self, filters): + def __init__(self, filters) -> None: self._filters = filters def is_ignored(self, path: str) -> Optional[bool]: @@ -297,7 +294,7 @@ def __init__( top_path: str, global_filters: List[IgnoreFilter], ignorecase: bool, - ): + ) -> None: self._path_filters: Dict[str, Optional[IgnoreFilter]] = {} self._top_path = top_path self._global_filters = global_filters diff --git a/dulwich/index.py b/dulwich/index.py index 672d6b67c..383d2586a 100644 --- a/dulwich/index.py +++ b/dulwich/index.py @@ -25,13 +25,30 @@ import stat import struct import sys -from typing import (Any, BinaryIO, Callable, Dict, Iterable, Iterator, List, - Optional, Tuple, Union) +from typing import ( + Any, + BinaryIO, + Callable, + Dict, + Iterable, + Iterator, + List, + Optional, + Tuple, + Union, +) from .file import GitFile from .object_store import iter_tree_contents -from .objects import (S_IFGITLINK, S_ISGITLINK, Blob, ObjectID, Tree, - hex_to_sha, sha_to_hex) +from .objects import ( + S_IFGITLINK, + S_ISGITLINK, + Blob, + ObjectID, + Tree, + hex_to_sha, + sha_to_hex, +) from .pack import ObjectContainer, SHA1Reader, SHA1Writer # TODO(jelmer): Switch to dataclass? @@ -78,6 +95,7 @@ def pathsplit(path: bytes) -> Tuple[bytes, bytes]: Args: path: The path to split. + Returns: Tuple with directory name and basename """ @@ -211,7 +229,7 @@ def write_cache_entry(f, name: bytes, entry: IndexEntry, version: int) -> None: class UnsupportedIndexFormat(Exception): """An unsupported index format was encountered.""" - def __init__(self, version): + def __init__(self, version) -> None: self.index_format_version = version @@ -274,6 +292,7 @@ def cleanup_mode(mode: int) -> int: Args: mode: Mode to clean up. + Returns: mode """ @@ -292,7 +311,7 @@ def cleanup_mode(mode: int) -> int: class Index: """A Git Index file.""" - def __init__(self, filename: Union[bytes, str], read=True): + def __init__(self, filename: Union[bytes, str], read=True) -> None: """Create an index object associated with the given filename. Args: @@ -310,7 +329,7 @@ def __init__(self, filename: Union[bytes, str], read=True): def path(self): return self._filename - def __repr__(self): + def __repr__(self) -> str: return "{}({!r})".format(self.__class__.__name__, self._filename) def write(self) -> None: @@ -371,13 +390,13 @@ def clear(self): """Remove all contents from this index.""" self._byname = {} - def __setitem__(self, name: bytes, x: IndexEntry): + def __setitem__(self, name: bytes, x: IndexEntry) -> None: assert isinstance(name, bytes) assert len(x) == len(IndexEntry._fields) # Remove the old entry if any self._byname[name] = IndexEntry(*x) - def __delitem__(self, name: bytes): + def __delitem__(self, name: bytes) -> None: assert isinstance(name, bytes) del self._byname[name] @@ -570,7 +589,7 @@ def index_entry_from_stat( class WindowsSymlinkPermissionError(PermissionError): - def __init__(self, errno, msg, filename): + def __init__(self, errno, msg, filename) -> None: super(PermissionError, self).__init__( errno, "Unable to create symlink; " "do you have developer mode enabled? %s" % msg, @@ -668,7 +687,7 @@ def build_index_from_tree( validate_path_element=validate_path_element_default, symlink_fn=None ): - """Generate and materialize index from a tree + """Generate and materialize index from a tree. Args: tree_id: Tree to materialize @@ -995,7 +1014,7 @@ class locked_index: Works as a context manager. """ - def __init__(self, path: Union[bytes, str]): + def __init__(self, path: Union[bytes, str]) -> None: self._path = path def __enter__(self): diff --git a/dulwich/lfs.py b/dulwich/lfs.py index 3a3f4fe9f..979336476 100644 --- a/dulwich/lfs.py +++ b/dulwich/lfs.py @@ -26,7 +26,7 @@ class LFSStore: """Stores objects on disk, indexed by SHA256.""" - def __init__(self, path): + def __init__(self, path) -> None: self.path = path @classmethod diff --git a/dulwich/line_ending.py b/dulwich/line_ending.py index e30bf480e..58f57932e 100644 --- a/dulwich/line_ending.py +++ b/dulwich/line_ending.py @@ -17,7 +17,7 @@ # and for a copy of the Apache # License, Version 2.0. # -"""All line-ending related functions, from conversions to config processing +"""All line-ending related functions, from conversions to config processing. Line-ending normalization is a complex beast. Here is some notes and details about how it seems to work. @@ -145,7 +145,7 @@ def convert_crlf_to_lf(text_hunk): - """Convert CRLF in text hunk into LF + """Convert CRLF in text hunk into LF. Args: text_hunk: A bytes string representing a text hunk @@ -155,7 +155,7 @@ def convert_crlf_to_lf(text_hunk): def convert_lf_to_crlf(text_hunk): - """Convert LF in text hunk into CRLF + """Convert LF in text hunk into CRLF. Args: text_hunk: A bytes string representing a text hunk @@ -167,7 +167,7 @@ def convert_lf_to_crlf(text_hunk): def get_checkout_filter(core_eol, core_autocrlf, git_attributes): - """Returns the correct checkout filter based on the passed arguments""" + """Returns the correct checkout filter based on the passed arguments.""" # TODO this function should process the git_attributes for the path and if # the text attribute is not defined, fallback on the # get_checkout_filter_autocrlf function with the autocrlf value @@ -175,7 +175,7 @@ def get_checkout_filter(core_eol, core_autocrlf, git_attributes): def get_checkin_filter(core_eol, core_autocrlf, git_attributes): - """Returns the correct checkin filter based on the passed arguments""" + """Returns the correct checkin filter based on the passed arguments.""" # TODO this function should process the git_attributes for the path and if # the text attribute is not defined, fallback on the # get_checkin_filter_autocrlf function with the autocrlf value @@ -183,7 +183,7 @@ def get_checkin_filter(core_eol, core_autocrlf, git_attributes): def get_checkout_filter_autocrlf(core_autocrlf): - """Returns the correct checkout filter base on autocrlf value + """Returns the correct checkout filter base on autocrlf value. Args: core_autocrlf: The bytes configuration value of core.autocrlf. @@ -191,7 +191,6 @@ def get_checkout_filter_autocrlf(core_autocrlf): Returns: Either None if no filter has to be applied or a function accepting a single argument, a binary text hunk """ - if core_autocrlf == b"true": return convert_lf_to_crlf @@ -199,7 +198,7 @@ def get_checkout_filter_autocrlf(core_autocrlf): def get_checkin_filter_autocrlf(core_autocrlf): - """Returns the correct checkin filter base on autocrlf value + """Returns the correct checkin filter base on autocrlf value. Args: core_autocrlf: The bytes configuration value of core.autocrlf. @@ -207,7 +206,6 @@ def get_checkin_filter_autocrlf(core_autocrlf): Returns: Either None if no filter has to be applied or a function accepting a single argument, a binary text hunk """ - if core_autocrlf == b"true" or core_autocrlf == b"input": return convert_crlf_to_lf @@ -217,10 +215,10 @@ def get_checkin_filter_autocrlf(core_autocrlf): class BlobNormalizer: """An object to store computation result of which filter to apply based - on configuration, gitattributes, path and operation (checkin or checkout) + on configuration, gitattributes, path and operation (checkin or checkout). """ - def __init__(self, config_stack, gitattributes): + def __init__(self, config_stack, gitattributes) -> None: self.config_stack = config_stack self.gitattributes = gitattributes @@ -243,7 +241,7 @@ def __init__(self, config_stack, gitattributes): ) def checkin_normalize(self, blob, tree_path): - """Normalize a blob during a checkin operation""" + """Normalize a blob during a checkin operation.""" if self.fallback_write_filter is not None: return normalize_blob( blob, self.fallback_write_filter, binary_detection=True @@ -252,7 +250,7 @@ def checkin_normalize(self, blob, tree_path): return blob def checkout_normalize(self, blob, tree_path): - """Normalize a blob during a checkout operation""" + """Normalize a blob during a checkout operation.""" if self.fallback_read_filter is not None: return normalize_blob( blob, self.fallback_read_filter, binary_detection=True @@ -264,7 +262,7 @@ def checkout_normalize(self, blob, tree_path): def normalize_blob(blob, conversion, binary_detection): """Takes a blob as input returns either the original blob if binary_detection is True and the blob content looks like binary, else - return a new blob with converted data + return a new blob with converted data. """ # Read the original blob data = blob.data @@ -286,7 +284,7 @@ def normalize_blob(blob, conversion, binary_detection): class TreeBlobNormalizer(BlobNormalizer): - def __init__(self, config_stack, git_attributes, object_store, tree=None): + def __init__(self, config_stack, git_attributes, object_store, tree=None) -> None: super().__init__(config_stack, git_attributes) if tree: self.existing_paths = { diff --git a/dulwich/lru_cache.py b/dulwich/lru_cache.py index ea66c6557..73ba838d5 100644 --- a/dulwich/lru_cache.py +++ b/dulwich/lru_cache.py @@ -21,8 +21,7 @@ """A simple least-recently-used (LRU) cache.""" -from typing import (Callable, Dict, Generic, Iterable, Iterator, Optional, - TypeVar) +from typing import Callable, Dict, Generic, Iterable, Iterator, Optional, TypeVar _null_key = object() @@ -40,7 +39,7 @@ class _LRUNode(Generic[K, V]): next_key: K size: Optional[int] - def __init__(self, key: K, value: V, cleanup=None): + def __init__(self, key: K, value: V, cleanup=None) -> None: self.prev = None self.next_key = _null_key # type: ignore self.key = key @@ -51,7 +50,7 @@ def __init__(self, key: K, value: V, cleanup=None): # actually costs us much of anything in normal usage self.size = None - def __repr__(self): + def __repr__(self) -> str: if self.prev is None: prev_key = None else: diff --git a/dulwich/mailmap.py b/dulwich/mailmap.py index c91ec50bc..592c222c8 100644 --- a/dulwich/mailmap.py +++ b/dulwich/mailmap.py @@ -61,7 +61,7 @@ def read_mailmap(f): class Mailmap: """Class for accessing a mailmap file.""" - def __init__(self, map=None): + def __init__(self, map=None) -> None: self._table = {} if map: for (canonical_identity, from_identity) in map: diff --git a/dulwich/object_store.py b/dulwich/object_store.py index d6eec790c..f60312ee8 100644 --- a/dulwich/object_store.py +++ b/dulwich/object_store.py @@ -28,8 +28,18 @@ import warnings from contextlib import suppress from io import BytesIO -from typing import (Callable, Dict, Iterable, Iterator, List, Optional, - Sequence, Set, Tuple, cast) +from typing import ( + Callable, + Dict, + Iterable, + Iterator, + List, + Optional, + Sequence, + Set, + Tuple, + cast, +) try: from typing import Protocol @@ -38,15 +48,43 @@ from .errors import NotTreeError from .file import GitFile -from .objects import (S_ISGITLINK, ZERO_SHA, Blob, Commit, ObjectID, ShaFile, - Tag, Tree, TreeEntry, hex_to_filename, hex_to_sha, - object_class, sha_to_hex, valid_hexsha) -from .pack import (PACK_SPOOL_FILE_MAX_SIZE, ObjectContainer, Pack, PackData, - PackedObjectContainer, PackFileDisappeared, PackHint, - PackIndexer, PackInflater, PackStreamCopier, UnpackedObject, - extend_pack, full_unpacked_object, - generate_unpacked_objects, iter_sha1, load_pack_index_file, - pack_objects_to_data, write_pack_data, write_pack_index) +from .objects import ( + S_ISGITLINK, + ZERO_SHA, + Blob, + Commit, + ObjectID, + ShaFile, + Tag, + Tree, + TreeEntry, + hex_to_filename, + hex_to_sha, + object_class, + sha_to_hex, + valid_hexsha, +) +from .pack import ( + PACK_SPOOL_FILE_MAX_SIZE, + ObjectContainer, + Pack, + PackData, + PackedObjectContainer, + PackFileDisappeared, + PackHint, + PackIndexer, + PackInflater, + PackStreamCopier, + UnpackedObject, + extend_pack, + full_unpacked_object, + generate_unpacked_objects, + iter_sha1, + load_pack_index_file, + pack_objects_to_data, + write_pack_data, + write_pack_index, +) from .protocol import DEPTH_INFINITE from .refs import PEELED_TAG_SUFFIX, Ref @@ -145,7 +183,7 @@ def tree_changes( change_type_same=False, rename_detector=None, ): - """Find the differences between the contents of two trees + """Find the differences between the contents of two trees. Args: source: SHA1 of the source tree @@ -157,7 +195,6 @@ def tree_changes( Returns: Iterator over tuples with (oldpath, newpath), (oldmode, newmode), (oldsha, newsha) """ - from .diff_tree import tree_changes for change in tree_changes( self, @@ -322,7 +359,7 @@ def close(self): class PackBasedObjectStore(BaseObjectStore): - def __init__(self, pack_compression_level=-1): + def __init__(self, pack_compression_level=-1) -> None: self._pack_cache = {} self.pack_compression_level = pack_compression_level @@ -374,7 +411,7 @@ def contains_packed(self, sha): pass return False - def __contains__(self, sha): + def __contains__(self, sha) -> bool: """Check if a particular object is present by SHA1. This method makes no distinction between loose and packed objects. @@ -655,7 +692,7 @@ def add_objects( class DiskObjectStore(PackBasedObjectStore): """Git-style object store that exists on disk.""" - def __init__(self, path, loose_compression_level=-1, pack_compression_level=-1): + def __init__(self, path, loose_compression_level=-1, pack_compression_level=-1) -> None: """Open an object store. Args: @@ -672,7 +709,7 @@ def __init__(self, path, loose_compression_level=-1, pack_compression_level=-1): self.loose_compression_level = loose_compression_level self.pack_compression_level = pack_compression_level - def __repr__(self): + def __repr__(self) -> str: return "<{}({!r})>".format(self.__class__.__name__, self.path) @classmethod @@ -956,7 +993,7 @@ def init(cls, path): class MemoryObjectStore(BaseObjectStore): """Object store that keeps all objects in memory.""" - def __init__(self): + def __init__(self) -> None: super().__init__() self._data = {} self.pack_compression_level = -1 @@ -999,7 +1036,7 @@ def get_raw(self, name: ObjectID): def __getitem__(self, name: ObjectID): return self._data[self._to_hexsha(name)].copy() - def __delitem__(self, name: ObjectID): + def __delitem__(self, name: ObjectID) -> None: """Delete an object from this store, for testing only.""" del self._data[self._to_hexsha(name)] @@ -1068,7 +1105,6 @@ def add_thin_pack(self, read_all, read_some, progress=None): read_some: Read function that returns at least one byte, but may not return the number of bytes requested. """ - f, commit, abort = self.add_pack() try: copier = PackStreamCopier(read_all, read_some, f) @@ -1185,7 +1221,7 @@ def __init__( progress=None, get_tagged=None, get_parents=lambda commit: commit.parents, - ): + ) -> None: self.object_store = object_store if shallow is None: shallow = set() @@ -1255,7 +1291,7 @@ def get_remote_has(self): return self.remote_has def add_todo(self, entries: Iterable[Tuple[ObjectID, Optional[bytes], Optional[int], bool]]): - self.objects_to_send.update([e for e in entries if not e[0] in self.sha_done]) + self.objects_to_send.update([e for e in entries if e[0] not in self.sha_done]) def __next__(self) -> Tuple[bytes, PackHint]: while True: @@ -1299,7 +1335,7 @@ class ObjectStoreGraphWalker: get_parents: Function to retrieve parents in the local repo """ - def __init__(self, local_heads, get_parents, shallow=None): + def __init__(self, local_heads, get_parents, shallow=None) -> None: """Create a new instance. Args: @@ -1409,7 +1445,7 @@ def commit_tree_changes(object_store, tree, changes): class OverlayObjectStore(BaseObjectStore): """Object store that can overlay multiple object stores.""" - def __init__(self, bases, add_store=None): + def __init__(self, bases, add_store=None) -> None: self.bases = bases self.add_store = add_store @@ -1489,8 +1525,7 @@ def read_packs_file(f): class BucketBasedObjectStore(PackBasedObjectStore): - """Object store implementation that uses a bucket store like S3 as backend. - """ + """Object store implementation that uses a bucket store like S3 as backend.""" def _iter_loose_objects(self): """Iterate over the SHAs of all loose objects.""" diff --git a/dulwich/objects.py b/dulwich/objects.py index 3f4b52a63..8fd9032b2 100644 --- a/dulwich/objects.py +++ b/dulwich/objects.py @@ -30,14 +30,29 @@ from collections import namedtuple from hashlib import sha1 from io import BytesIO -from typing import (BinaryIO, Dict, Iterable, Iterator, List, Optional, Tuple, - Type, Union) +from typing import ( + BinaryIO, + Dict, + Iterable, + Iterator, + List, + Optional, + Tuple, + Type, + Union, +) from _hashlib import HASH -from .errors import (ChecksumMismatch, FileFormatException, NotBlobError, - NotCommitError, NotTagError, NotTreeError, - ObjectFormatException) +from .errors import ( + ChecksumMismatch, + FileFormatException, + NotBlobError, + NotCommitError, + NotTagError, + NotTreeError, + ObjectFormatException, +) from .file import GitFile ZERO_SHA = b"0" * 40 @@ -91,14 +106,14 @@ def _decompress(string): def sha_to_hex(sha): - """Takes a string and returns the hex of the sha within""" + """Takes a string and returns the hex of the sha within.""" hexsha = binascii.hexlify(sha) assert len(hexsha) == 40, "Incorrect length of sha1 string: %r" % hexsha return hexsha def hex_to_sha(hex): - """Takes a hex sha and returns a binary sha""" + """Takes a hex sha and returns a binary sha.""" assert len(hex) == 40, "Incorrect length of hexsha: %s" % hex try: return binascii.unhexlify(hex) @@ -236,7 +251,7 @@ class FixedSha: __slots__ = ("_hexsha", "_sha") - def __init__(self, hexsha): + def __init__(self, hexsha) -> None: if getattr(hexsha, "encode", None) is not None: hexsha = hexsha.encode("ascii") if not isinstance(hexsha, bytes): @@ -407,8 +422,8 @@ def _parse_file(cls, f): obj._parse_object(map) return obj - def __init__(self): - """Don't call this directly""" + def __init__(self) -> None: + """Don't call this directly.""" self._sha = None self._chunked_text = [] self._needs_serialization = True @@ -530,7 +545,7 @@ def sha(self): return self._sha def copy(self): - """Create a new copy of this SHA1 object from its raw string""" + """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) @@ -541,7 +556,7 @@ def id(self): """The hex SHA of this object.""" return self.sha().hexdigest().encode("ascii") - def __repr__(self): + def __repr__(self) -> str: return "<{} {}>".format(self.__class__.__name__, self.id) def __ne__(self, other): @@ -575,7 +590,7 @@ class Blob(ShaFile): _chunked_text: List[bytes] - def __init__(self): + def __init__(self) -> None: super().__init__() self._chunked_text = [] self._needs_serialization = False @@ -666,7 +681,7 @@ def _parse_message(chunks: Iterable[bytes]) -> Iterator[Tuple[Optional[bytes], O eof = False def _strip_last_newline(value): - """Strip the last newline from value""" + """Strip the last newline from value.""" if value and value.endswith(b"\n"): return value[:-1] return value @@ -736,7 +751,7 @@ class Tag(ShaFile): _tagger: Optional[bytes] - def __init__(self): + def __init__(self) -> None: super().__init__() self._tagger = None self._tag_time = None @@ -806,7 +821,7 @@ def _serialize(self): return list(_format_message(headers, body)) def _deserialize(self, chunks): - """Grab the metadata attached to the tag""" + """Grab the metadata attached to the tag.""" self._tagger = None self._tag_time = None self._tag_timezone = None @@ -943,6 +958,7 @@ def parse_tree(text, strict=False): Args: text: Serialized text to parse Returns: iterator of tuples of (name, mode, sha) + Raises: ObjectFormatException: if the object was malformed in some way """ @@ -1045,20 +1061,20 @@ def pretty_format_tree_entry(name, mode, hexsha, encoding="utf-8") -> str: class SubmoduleEncountered(Exception): """A submodule was encountered while resolving a path.""" - def __init__(self, path, sha): + def __init__(self, path, sha) -> None: self.path = path self.sha = sha class Tree(ShaFile): - """A Git tree object""" + """A Git tree object.""" type_name = b"tree" type_num = 2 __slots__ = "_entries" - def __init__(self): + def __init__(self) -> None: super().__init__() self._entries = {} @@ -1069,13 +1085,13 @@ def from_path(cls, filename): raise NotTreeError(filename) return tree - def __contains__(self, name): + def __contains__(self, name) -> bool: return name in self._entries def __getitem__(self, name): return self._entries[name] - def __setitem__(self, name, value): + def __setitem__(self, name, value) -> None: """Set a tree entry by name. Args: @@ -1088,11 +1104,11 @@ def __setitem__(self, name, value): self._entries[name] = (mode, hexsha) self._needs_serialization = True - def __delitem__(self, name): + def __delitem__(self, name) -> None: del self._entries[name] self._needs_serialization = True - def __len__(self): + def __len__(self) -> int: return len(self._entries) def __iter__(self): @@ -1128,7 +1144,7 @@ def items(self): return list(self.iteritems()) def _deserialize(self, chunks): - """Grab the entries in the tree""" + """Grab the entries in the tree.""" try: parsed_entries = parse_tree(b"".join(chunks)) except ValueError as exc: @@ -1218,7 +1234,7 @@ def parse_timezone(text): # cgit parses the first character as the sign, and the rest # as an integer (using strtol), which could also be negative. # We do the same for compatibility. See #697828. - if not text[0] in b"+-": + if text[0] not in b"+-": raise ValueError("Timezone must start with + or - (%(text)s)" % vars()) sign = text[:1] offset = int(text[1:]) @@ -1254,7 +1270,7 @@ def format_timezone(offset, unnecessary_negative_timezone=False): def parse_time_entry(value): - """Parse event + """Parse event. Args: value: Bytes representing a git commit/tag line @@ -1279,8 +1295,7 @@ def parse_time_entry(value): def format_time_entry(person, time, timezone_info): - """Format an event - """ + """Format an event.""" (timezone, timezone_neg_utc) = timezone_info return b" ".join([ person, @@ -1341,7 +1356,7 @@ def parse_commit(chunks): class Commit(ShaFile): - """A git commit object""" + """A git commit object.""" type_name = b"commit" type_num = 1 @@ -1364,7 +1379,7 @@ class Commit(ShaFile): "_gpgsig", ) - def __init__(self): + def __init__(self) -> None: super().__init__() self._parents = [] self._encoding = None diff --git a/dulwich/objectspec.py b/dulwich/objectspec.py index 22a759bba..b3ae58e50 100644 --- a/dulwich/objectspec.py +++ b/dulwich/objectspec.py @@ -197,7 +197,7 @@ def parse_commit_range(repo: "Repo", committishs: Union[str, bytes]) -> Iterator class AmbiguousShortId(Exception): """The short id is ambiguous.""" - def __init__(self, prefix, options): + def __init__(self, prefix, options) -> None: self.prefix = prefix self.options = options diff --git a/dulwich/pack.py b/dulwich/pack.py index 0e9bf8a58..9b31e7eed 100644 --- a/dulwich/pack.py +++ b/dulwich/pack.py @@ -46,14 +46,27 @@ import struct import sys from itertools import chain -from typing import (BinaryIO, Callable, Deque, Dict, Generic, Iterable, - Iterator, List, Optional, Sequence, Set, Tuple, TypeVar, - Union) +from typing import ( + BinaryIO, + Callable, + Deque, + Dict, + Generic, + Iterable, + Iterator, + List, + Optional, + Sequence, + Set, + Tuple, + TypeVar, + Union, +) try: from typing import Protocol except ImportError: # python << 3.8 - from typing_extensions import Protocol # type: ignore + from typing_extensions import Protocol # type: ignore import warnings import zlib @@ -156,7 +169,7 @@ def take_msb_bytes(read: Callable[[int], bytes], crc32: Optional[int] = None) -> class PackFileDisappeared(Exception): - def __init__(self, obj): + def __init__(self, obj) -> None: self.obj = obj @@ -191,7 +204,7 @@ class UnpackedObject: # TODO(dborowitz): read_zlib_chunks and unpack_object could very well be # methods of this object. - def __init__(self, pack_type_num, *, delta_base=None, decomp_len=None, crc32=None, sha=None, decomp_chunks=None, offset=None): + def __init__(self, pack_type_num, *, delta_base=None, decomp_len=None, crc32=None, sha=None, decomp_chunks=None, offset=None) -> None: self.offset = offset self._sha = sha self.pack_type_num = pack_type_num @@ -244,7 +257,7 @@ def __eq__(self, other): def __ne__(self, other): return not (self == other) - def __repr__(self): + def __repr__(self) -> str: data = ["{}={!r}".format(s, getattr(self, s)) for s in self.__slots__] return "{}({})".format(self.__class__.__name__, ", ".join(data)) @@ -276,6 +289,7 @@ def read_zlib_chunks( include_comp: If True, include compressed data in the result. buffer_size: Size of the read buffer. Returns: Leftover unused data from the decompression. + Raises: zlib.error: if a decompression error occurred. """ @@ -503,7 +517,7 @@ def check(self) -> None: class MemoryPackIndex(PackIndex): """Pack index that is stored entirely in memory.""" - def __init__(self, entries, pack_checksum=None): + def __init__(self, entries, pack_checksum=None) -> None: """Create a new MemoryPackIndex. Args: @@ -521,7 +535,7 @@ def __init__(self, entries, pack_checksum=None): def get_pack_checksum(self): return self._pack_checksum - def __len__(self): + def __len__(self) -> int: return len(self._entries) def object_offset(self, sha): @@ -561,7 +575,7 @@ class FilePackIndex(PackIndex): _fan_out_table: List[int] - def __init__(self, filename, file=None, contents=None, size=None): + def __init__(self, filename, file=None, contents=None, size=None) -> None: """Create a pack index object. Provide it with the name of the index file to consider, and it will map @@ -711,7 +725,7 @@ def _object_offset(self, sha: bytes) -> int: class PackIndex1(FilePackIndex): """Version 1 Pack Index file.""" - def __init__(self, filename: str, file=None, contents=None, size=None): + def __init__(self, filename: str, file=None, contents=None, size=None) -> None: super().__init__(filename, file, contents, size) self.version = 1 self._fan_out_table = self._read_fan_out_table(0) @@ -736,7 +750,7 @@ def _unpack_crc32_checksum(self, i): class PackIndex2(FilePackIndex): """Version 2 Pack Index file.""" - def __init__(self, filename: str, file=None, contents=None, size=None): + def __init__(self, filename: str, file=None, contents=None, size=None) -> None: super().__init__(filename, file, contents, size) if self._contents[:4] != b"\377tOc": raise AssertionError("Not a v2 pack index file") @@ -967,7 +981,7 @@ def recv(self, size): return data return self._read(self.read_some, size) - def __len__(self): + def __len__(self) -> int: return self._num_objects def read_objects(self, compute_crc32=False) -> Iterator[UnpackedObject]: @@ -984,6 +998,7 @@ def read_objects(self, compute_crc32=False) -> Iterator[UnpackedObject]: decomp_chunks decomp_len crc32 (if compute_crc32 is True) + Raises: ChecksumMismatch: if the checksum of the pack contents does not match the checksum in the pack trailer. @@ -1030,7 +1045,7 @@ class PackStreamCopier(PackStreamReader): appropriate and written out to the given file-like object. """ - def __init__(self, read_all, read_some, outfile, delta_iter=None): + def __init__(self, read_all, read_some, outfile, delta_iter=None) -> None: """Initialize the copier. Args: @@ -1135,7 +1150,7 @@ class PackData: position. It will all just throw a zlib or KeyError. """ - def __init__(self, filename, file=None, size=None): + def __init__(self, filename, file=None, size=None) -> None: """Create a PackData object representing the pack in the given filename. The file must exist and stay readable until the object is disposed of. @@ -1199,7 +1214,7 @@ def _get_size(self): raise AssertionError(errmsg) return self._size - def __len__(self): + def __len__(self) -> int: """Returns the number of objects in this pack.""" return self._num_objects @@ -1306,8 +1321,7 @@ def check(self): raise ChecksumMismatch(stored, actual) def get_unpacked_object_at(self, offset: int, *, include_comp: bool = False) -> UnpackedObject: - """Given offset in the packfile return a UnpackedObject. - """ + """Given offset in the packfile return a UnpackedObject.""" assert offset >= self._header_size self._file.seek(offset) unpacked, _ = unpack_object(self._file.read, include_comp=include_comp) @@ -1522,7 +1536,7 @@ def _result(self, unpacked): class SHA1Reader: """Wrapper for file-like object that remembers the SHA1 of its data.""" - def __init__(self, f): + def __init__(self, f) -> None: self.f = f self.sha1 = sha1(b"") @@ -1546,7 +1560,7 @@ def tell(self): class SHA1Writer: """Wrapper for file-like object that remembers the SHA1 of its data.""" - def __init__(self, f): + def __init__(self, f) -> None: self.f = f self.length = 0 self.sha1 = sha1(b"") @@ -1799,7 +1813,7 @@ def pack_objects_to_data( delta_window_size: Optional[int] = None, ofs_delta: bool = True, progress=None) -> Tuple[int, Iterator[UnpackedObject]]: - """Create pack data from objects + """Create pack data from objects. Args: objects: Pack objects @@ -1837,7 +1851,7 @@ def generate_unpacked_objects( ofs_delta: bool = True, other_haves: Optional[Set[bytes]] = None, progress=None) -> Iterator[UnpackedObject]: - """Create pack data from objects + """Create pack data from objects. Args: objects: Pack objects @@ -1941,7 +1955,7 @@ def write_pack_objects( class PackChunkGenerator: - def __init__(self, num_records=None, records=None, progress=None, compression_level=-1, reuse_compressed=True): + def __init__(self, num_records=None, records=None, progress=None, compression_level=-1, reuse_compressed=True) -> None: self.cs = sha1(b"") self.entries = {} self._it = self._pack_data_chunks( @@ -2256,7 +2270,7 @@ class Pack: _data: Optional[PackData] _idx: Optional[PackIndex] - def __init__(self, basename, resolve_ext_ref: Optional[ResolveExtRefFn] = None): + def __init__(self, basename, resolve_ext_ref: Optional[ResolveExtRefFn] = None) -> None: self._basename = basename self._data = None self._idx = None @@ -2269,7 +2283,8 @@ def __init__(self, basename, resolve_ext_ref: Optional[ResolveExtRefFn] = None): @classmethod def from_lazy_objects(cls, data_fn, idx_fn): """Create a new pack object from callables to load pack data and - index objects.""" + index objects. + """ ret = cls("") ret._data_load = data_fn ret._idx_load = idx_fn @@ -2325,11 +2340,11 @@ def __exit__(self, exc_type, exc_val, exc_tb): def __eq__(self, other): return isinstance(self, type(other)) and self.index == other.index - def __len__(self): + def __len__(self) -> int: """Number of entries in this pack.""" return len(self.index) - def __repr__(self): + def __repr__(self) -> str: return "{}({!r})".format(self.__class__.__name__, self._basename) def __iter__(self): @@ -2592,7 +2607,9 @@ def extend_pack(f: BinaryIO, object_ids: Set[ObjectID], get_raw, *, compression_ try: - from dulwich._pack import apply_delta # type: ignore # noqa: F811 - from dulwich._pack import bisect_find_sha # type: ignore # noqa: F811 + from dulwich._pack import ( + apply_delta, # type: ignore # noqa: F811 + bisect_find_sha, # type: ignore # noqa: F811 + ) except ImportError: pass diff --git a/dulwich/patch.py b/dulwich/patch.py index ffdfdc3cf..e4076fea2 100644 --- a/dulwich/patch.py +++ b/dulwich/patch.py @@ -41,6 +41,7 @@ def write_commit_patch(f, commit, contents, progress, version=None, encoding=Non Args: commit: Commit object progress: Tuple with current patch number and total. + Returns: tuple with filename and contents """ @@ -101,7 +102,7 @@ def get_summary(commit): # Unified Diff def _format_range_unified(start, stop): - 'Convert range to the "ed" format' + 'Convert range to the "ed" format.' # Per the diff spec at http://www.unix.org/single_unix_specification/ beginning = start + 1 # lines start numbering with one length = stop - start diff --git a/dulwich/porcelain.py b/dulwich/porcelain.py index d63523f09..f61482b10 100644 --- a/dulwich/porcelain.py +++ b/dulwich/porcelain.py @@ -78,28 +78,57 @@ from .archive import tar_stream from .client import get_transport_and_path from .config import Config, ConfigFile, StackedConfig, read_submodules -from .diff_tree import (CHANGE_ADD, CHANGE_COPY, CHANGE_DELETE, CHANGE_MODIFY, - CHANGE_RENAME, RENAME_CHANGE_TYPES) +from .diff_tree import ( + CHANGE_ADD, + CHANGE_COPY, + CHANGE_DELETE, + CHANGE_MODIFY, + CHANGE_RENAME, + RENAME_CHANGE_TYPES, +) from .errors import SendPackError from .file import ensure_dir_exists from .graph import can_fast_forward from .ignore import IgnoreFilterManager -from .index import (_fs_to_tree_path, blob_from_path_and_stat, - build_file_from_blob, get_unstaged_changes, - index_entry_from_stat) +from .index import ( + _fs_to_tree_path, + blob_from_path_and_stat, + build_file_from_blob, + get_unstaged_changes, + index_entry_from_stat, +) from .object_store import iter_tree_contents, tree_lookup_path -from .objects import (Commit, Tag, format_timezone, parse_timezone, - pretty_format_tree_entry) -from .objectspec import (parse_commit, parse_object, parse_ref, - parse_reftuples, parse_tree, to_bytes) +from .objects import ( + Commit, + Tag, + format_timezone, + parse_timezone, + pretty_format_tree_entry, +) +from .objectspec import ( + parse_commit, + parse_object, + parse_ref, + parse_reftuples, + parse_tree, + to_bytes, +) from .pack import write_pack_from_container, write_pack_index from .patch import write_tree_diff from .protocol import ZERO_SHA, Protocol -from .refs import (LOCAL_BRANCH_PREFIX, LOCAL_REMOTE_PREFIX, LOCAL_TAG_PREFIX, - _import_remote_refs) +from .refs import ( + LOCAL_BRANCH_PREFIX, + LOCAL_REMOTE_PREFIX, + LOCAL_TAG_PREFIX, + _import_remote_refs, +) from .repo import BaseRepo, Repo -from .server import (FileSystemBackend, ReceivePackHandler, TCPGitServer, - UploadPackHandler) +from .server import ( + FileSystemBackend, + ReceivePackHandler, + TCPGitServer, + UploadPackHandler, +) from .server import update_server_info as server_update_server_info # Module level tuple definition for status output @@ -130,9 +159,9 @@ def write(self, b): class Error(Exception): - """Porcelain-based error. """ + """Porcelain-based error.""" - def __init__(self, msg): + def __init__(self, msg) -> None: super().__init__(msg) @@ -162,7 +191,7 @@ def parse_timezone_format(tz_str): Returns: Timezone offset as integer Raises: TimezoneFormatError: if timezone information cannot be extracted - """ + """ import re # Git internal format @@ -203,7 +232,7 @@ def parse_timezone_format(tz_str): def get_user_timezones(): """Retrieve local timezone as described in https://raw.githubusercontent.com/git/git/v2.3.0/Documentation/date-formats.txt - Returns: A tuple containing author timezone, committer timezone + Returns: A tuple containing author timezone, committer timezone. """ local_timezone = time.localtime().tm_gmtoff @@ -286,7 +315,7 @@ def path_to_tree_path(repopath, path, tree_encoding=DEFAULT_ENCODING): class DivergedBranches(Error): """Branches have diverged and fast-forward is not possible.""" - def __init__(self, current_sha, new_sha): + def __init__(self, current_sha, new_sha) -> None: self.current_sha = current_sha self.new_sha = new_sha @@ -321,7 +350,6 @@ def archive( outstream: Output stream (defaults to stdout) errstream: Error stream (defaults to stderr) """ - if committish is None: committish = "HEAD" with open_repo_closing(repo) as repo_obj: @@ -566,7 +594,7 @@ def add(repo=".", paths=None): def _is_subdir(subdir, parentdir): - """Check whether subdir is parentdir or a subdir of parentdir + """Check whether subdir is parentdir or a subdir of parentdir. If parentdir or subdir is a relative path, it will be disamgibuated relative to the pwd. @@ -578,7 +606,7 @@ def _is_subdir(subdir, parentdir): # TODO: option to remove ignored files also, in line with `git clean -fdx` def clean(repo=".", target_dir=None): - """Remove any untracked files from the target directory recursively + """Remove any untracked files from the target directory recursively. Equivalent to running ``git clean -fd`` in target_dir. @@ -1016,7 +1044,6 @@ def tag_create( pass True to use default GPG key, pass a str containing Key ID to use a specific GPG key) """ - with open_repo_closing(repo) as r: object = parse_object(r, objectish) @@ -1087,7 +1114,6 @@ def reset(repo, mode, treeish="HEAD"): mode: Mode ("hard", "soft", "mixed") treeish: Treeish to reset to """ - if mode != "hard": raise Error("hard is the only mode currently supported") @@ -1129,7 +1155,7 @@ def push( force=False, **kwargs ): - """Remote push with dulwich via dulwich.client + """Remote push with dulwich via dulwich.client. Args: repo: Path to repository @@ -1139,7 +1165,6 @@ def push( errstream: A stream file to write errors force: Force overwriting refs """ - # Open the repo with open_repo_closing(repo) as r: if refspecs is None: @@ -1215,7 +1240,7 @@ def pull( force=False, **kwargs ): - """Pull from remote via dulwich.client + """Pull from remote via dulwich.client. Args: repo: Path to repository @@ -1315,7 +1340,7 @@ def status(repo=".", ignored=False, untracked_files="all"): def _walk_working_dir_paths(frompath, basepath, prune_dirnames=None): - """Get path, is_dir for files in working dir from frompath + """Get path, is_dir for files in working dir from frompath. Args: frompath: Path to begin walk @@ -1462,8 +1487,12 @@ def web_daemon(path=".", address=None, port=None): address: Optional address to listen on (defaults to ::) port: Optional port to listen on (defaults to 80) """ - from .web import (WSGIRequestHandlerLogger, WSGIServerLogger, make_server, - make_wsgi_chain) + from .web import ( + WSGIRequestHandlerLogger, + WSGIServerLogger, + make_server, + make_wsgi_chain, + ) backend = FileSystemBackend(path) app = make_wsgi_chain(backend) @@ -1782,7 +1811,7 @@ def remote_add(repo: Repo, name: Union[bytes, str], url: Union[bytes, str]): def remote_remove(repo: Repo, name: Union[bytes, str]): - """Remove a remote + """Remove a remote. Args: repo: Path to the repository @@ -1890,7 +1919,7 @@ def _update_head_during_checkout_branch(repo, target): def checkout_branch(repo, target: Union[bytes, str], force: bool = False): - """switch branches or restore working tree files. + """Switch branches or restore working tree files. The implementation of this function will probably not scale well for branches with lots of local changes. diff --git a/dulwich/protocol.py b/dulwich/protocol.py index dc0d23dd3..2d6e10f5c 100644 --- a/dulwich/protocol.py +++ b/dulwich/protocol.py @@ -178,7 +178,7 @@ class Protocol: Documentation/technical/protocol-common.txt """ - def __init__(self, read, write, close=None, report_activity=None): + def __init__(self, read, write, close=None, report_activity=None) -> None: self.read = read self.write = write self._close = close @@ -256,6 +256,7 @@ def unread_pkt_line(self, data): Args: data: The data to unread, without the length prefix. + Raises: ValueError: If more than one pkt-line is unread. """ @@ -315,7 +316,7 @@ def send_cmd(self, cmd, *args): self.write_pkt_line(format_cmd_pkt(cmd, *args)) def read_cmd(self): - """Read a command and some arguments from the git client + """Read a command and some arguments from the git client. Only used for the TCP git protocol (git://). @@ -342,7 +343,7 @@ class ReceivableProtocol(Protocol): def __init__( self, recv, write, close=None, report_activity=None, rbufsize=_RBUFSIZE - ): + ) -> None: super().__init__( self.read, write, close=close, report_activity=report_activity ) @@ -483,7 +484,7 @@ class BufferedPktLineWriter: (including length prefix) reach the buffer size. """ - def __init__(self, write, bufsize=65515): + def __init__(self, write, bufsize=65515) -> None: """Initialize the BufferedPktLineWriter. Args: @@ -522,7 +523,7 @@ def flush(self): class PktLineParser: """Packet line parser that hands completed packets off to a callback.""" - def __init__(self, handle_pkt): + def __init__(self, handle_pkt) -> None: self.handle_pkt = handle_pkt self._readahead = BytesIO() diff --git a/dulwich/reflog.py b/dulwich/reflog.py index 2be241c98..9bea44857 100644 --- a/dulwich/reflog.py +++ b/dulwich/reflog.py @@ -18,8 +18,7 @@ # License, Version 2.0. # -"""Utilities for reading and generating reflogs. -""" +"""Utilities for reading and generating reflogs.""" import collections diff --git a/dulwich/refs.py b/dulwich/refs.py index 9f6f70de4..815907d56 100644 --- a/dulwich/refs.py +++ b/dulwich/refs.py @@ -19,9 +19,7 @@ # -"""Ref handling. - -""" +"""Ref handling.""" import os import warnings from contextlib import suppress @@ -49,7 +47,7 @@ class SymrefLoop(Exception): """There is a loop between one or more symrefs.""" - def __init__(self, ref, depth): + def __init__(self, ref, depth) -> None: self.ref = ref self.depth = depth @@ -103,7 +101,7 @@ def check_ref_format(refname: Ref): class RefsContainer: """A container for refs.""" - def __init__(self, logger=None): + def __init__(self, logger=None) -> None: self._logger = logger def _log( @@ -260,6 +258,7 @@ class needs to be able to touch HEAD. Also, check_ref_format expects Args: name: The name of the reference. + Raises: KeyError: if a refname is not HEAD or is otherwise not valid. """ @@ -311,7 +310,7 @@ def follow(self, name): raise SymrefLoop(name, depth) return refnames, contents - def __contains__(self, refname): + def __contains__(self, refname) -> bool: if self.read_ref(refname): return True return False @@ -362,7 +361,7 @@ def add_if_new(self, name, ref, committer=None, timestamp=None, """ raise NotImplementedError(self.add_if_new) - def __setitem__(self, name, ref): + def __setitem__(self, name, ref) -> None: """Set a reference name to point to the given SHA1. This method follows all symbolic references if applicable for the @@ -402,7 +401,7 @@ def remove_if_equals( """ raise NotImplementedError(self.remove_if_equals) - def __delitem__(self, name): + def __delitem__(self, name) -> None: """Remove a refname. This method does not follow symbolic references, even if applicable for @@ -440,7 +439,7 @@ class DictRefsContainer(RefsContainer): threadsafe. """ - def __init__(self, refs, logger=None): + def __init__(self, refs, logger=None) -> None: super().__init__(logger=logger) self._refs = refs self._peeled = {} @@ -581,7 +580,7 @@ def _update_peeled(self, peeled): class InfoRefsContainer(RefsContainer): """Refs container that reads refs from a info/refs file.""" - def __init__(self, f): + def __init__(self, f) -> None: self._refs = {} self._peeled = {} for line in f.readlines(): @@ -615,7 +614,7 @@ def get_peeled(self, name): class DiskRefsContainer(RefsContainer): """Refs container that reads refs from disk.""" - def __init__(self, path, worktree_path=None, logger=None): + def __init__(self, path, worktree_path=None, logger=None) -> None: super().__init__(logger=logger) if getattr(path, "encode", None) is not None: path = os.fsencode(path) @@ -628,7 +627,7 @@ def __init__(self, path, worktree_path=None, logger=None): self._packed_refs = None self._peeled_refs = None - def __repr__(self): + def __repr__(self) -> str: return "{}({!r})".format(self.__class__.__name__, self.path) def subkeys(self, base): @@ -775,6 +774,7 @@ def read_loose_ref(self, name): name: the refname to read, relative to refpath Returns: The contents of the ref file, or None if the file does not exist. + Raises: IOError: if any other error occurs """ @@ -1166,7 +1166,7 @@ def is_local_branch(x): def strip_peeled_refs(refs): - """Remove all peeled refs""" + """Remove all peeled refs.""" return { ref: sha for (ref, sha) in refs.items() @@ -1187,8 +1187,7 @@ def _set_origin_head(refs, origin, origin_head): def _set_default_branch( refs: RefsContainer, origin: bytes, origin_head: bytes, branch: bytes, ref_message: Optional[bytes]) -> bytes: - """Set the default branch. - """ + """Set the default branch.""" origin_base = b"refs/remotes/" + origin + b"/" if branch: origin_ref = origin_base + branch diff --git a/dulwich/repo.py b/dulwich/repo.py index 55a4dba0a..e653b28ec 100644 --- a/dulwich/repo.py +++ b/dulwich/repo.py @@ -34,36 +34,85 @@ import time import warnings from io import BytesIO -from typing import (TYPE_CHECKING, BinaryIO, Callable, Dict, FrozenSet, - Iterable, List, Optional, Set, Tuple, Union) +from typing import ( + TYPE_CHECKING, + BinaryIO, + Callable, + Dict, + FrozenSet, + Iterable, + List, + Optional, + Set, + Tuple, + Union, +) if TYPE_CHECKING: # There are no circular imports here, but we try to defer imports as long # as possible to reduce start-up time for anything that doesn't need # these imports. - from .config import StackedConfig, ConfigFile + from .config import ConfigFile, StackedConfig from .index import Index -from .errors import (CommitError, HookError, NoIndexPresent, NotBlobError, - NotCommitError, NotGitRepository, NotTagError, - NotTreeError, RefFormatError) +from .errors import ( + CommitError, + HookError, + NoIndexPresent, + NotBlobError, + NotCommitError, + NotGitRepository, + NotTagError, + NotTreeError, + RefFormatError, +) from .file import GitFile -from .hooks import (CommitMsgShellHook, Hook, PostCommitShellHook, - PostReceiveShellHook, PreCommitShellHook) +from .hooks import ( + CommitMsgShellHook, + Hook, + PostCommitShellHook, + PostReceiveShellHook, + PreCommitShellHook, +) from .line_ending import BlobNormalizer, TreeBlobNormalizer -from .object_store import (DiskObjectStore, MemoryObjectStore, - MissingObjectFinder, ObjectStoreGraphWalker, - PackBasedObjectStore, peel_sha) -from .objects import (Blob, Commit, ObjectID, ShaFile, Tag, Tree, check_hexsha, - valid_hexsha) +from .object_store import ( + DiskObjectStore, + MemoryObjectStore, + MissingObjectFinder, + ObjectStoreGraphWalker, + PackBasedObjectStore, + peel_sha, +) +from .objects import ( + Blob, + Commit, + ObjectID, + ShaFile, + Tag, + Tree, + check_hexsha, + valid_hexsha, +) from .pack import generate_unpacked_objects -from .refs import (ANNOTATED_TAG_SUFFIX, LOCAL_BRANCH_PREFIX, # noqa: F401 - LOCAL_TAG_PREFIX, SYMREF, - DictRefsContainer, DiskRefsContainer, InfoRefsContainer, - Ref, RefsContainer, _set_default_branch, _set_head, - _set_origin_head, check_ref_format, read_packed_refs, - read_packed_refs_with_peeled, serialize_refs, - write_packed_refs) +from .refs import ( # noqa: F401 + ANNOTATED_TAG_SUFFIX, + LOCAL_BRANCH_PREFIX, + LOCAL_TAG_PREFIX, + SYMREF, + DictRefsContainer, + DiskRefsContainer, + InfoRefsContainer, + Ref, + RefsContainer, + _set_default_branch, + _set_head, + _set_origin_head, + check_ref_format, + read_packed_refs, + read_packed_refs_with_peeled, + serialize_refs, + write_packed_refs, +) CONTROLDIR = ".git" OBJECTDIR = "objects" @@ -88,9 +137,9 @@ class InvalidUserIdentity(Exception): - """User identity is not of the format 'user '""" + """User identity is not of the format 'user '.""" - def __init__(self, identity): + def __init__(self, identity) -> None: self.identity = identity @@ -200,7 +249,7 @@ def check_user_identity(identity): def parse_graftpoints( graftpoints: Iterable[bytes], ) -> Dict[bytes, List[bytes]]: - """Convert a list of graftpoints into a dict + """Convert a list of graftpoints into a dict. Args: graftpoints: Iterator of graftpoint lines @@ -231,7 +280,7 @@ def parse_graftpoints( def serialize_graftpoints(graftpoints: Dict[bytes, List[bytes]]) -> bytes: - """Convert a dictionary of grafts into string + """Convert a dictionary of grafts into string. The graft dictionary is: : [*] @@ -275,7 +324,7 @@ def _set_filesystem_hidden(path): class ParentsProvider: - def __init__(self, store, grafts={}, shallows=[]): + def __init__(self, store, grafts={}, shallows=[]) -> None: self.store = store self.grafts = grafts self.shallows = set(shallows) @@ -305,7 +354,7 @@ class BaseRepo: repository """ - def __init__(self, object_store: PackBasedObjectStore, refs: RefsContainer): + def __init__(self, object_store: PackBasedObjectStore, refs: RefsContainer) -> None: """Open a repository. This shouldn't be called directly, but rather through one of the @@ -497,7 +546,7 @@ class DummyMissingObjectFinder: def get_remote_has(self): return None - def __len__(self): + def __len__(self) -> int: return 0 def __iter__(self): @@ -642,8 +691,7 @@ def get_config(self) -> "ConfigFile": raise NotImplementedError(self.get_config) def get_worktree_config(self) -> "ConfigFile": - """Retrieve the worktree config object. - """ + """Retrieve the worktree config object.""" raise NotImplementedError(self.get_worktree_config) def get_description(self): @@ -795,7 +843,7 @@ def __contains__(self, name: bytes) -> bool: else: return name in self.refs - def __setitem__(self, name: bytes, value: Union[ShaFile, bytes]): + def __setitem__(self, name: bytes, value: Union[ShaFile, bytes]) -> None: """Set a ref. Args: @@ -812,7 +860,7 @@ def __setitem__(self, name: bytes, value: Union[ShaFile, bytes]): else: raise ValueError(name) - def __delitem__(self, name: bytes): + def __delitem__(self, name: bytes) -> None: """Remove a ref. Args: @@ -830,12 +878,11 @@ def _get_user_identity(self, config: "StackedConfig", return get_user_identity(config) def _add_graftpoints(self, updated_graftpoints: Dict[bytes, List[bytes]]): - """Add or modify graftpoints + """Add or modify graftpoints. Args: updated_graftpoints: Dict of commit shas to list of parent shas """ - # Simple validation for commit, parents in updated_graftpoints.items(): for sha in [commit] + parents: @@ -844,7 +891,7 @@ def _add_graftpoints(self, updated_graftpoints: Dict[bytes, List[bytes]]): self._graftpoints.update(updated_graftpoints) def _remove_graftpoints(self, to_remove: List[bytes] = []) -> None: - """Remove graftpoints + """Remove graftpoints. Args: to_remove: List of commit shas @@ -904,7 +951,6 @@ def do_commit( # noqa: C901 Returns: New commit SHA1 """ - try: if not no_verify: self.hooks["pre-commit"].execute() @@ -1043,14 +1089,14 @@ def read_gitfile(f): class UnsupportedVersion(Exception): """Unsupported repository version.""" - def __init__(self, version): + def __init__(self, version) -> None: self.version = version class UnsupportedExtension(Exception): """Unsupported repository extension.""" - def __init__(self, extension): + def __init__(self, extension) -> None: self.extension = extension @@ -1067,7 +1113,6 @@ class Repo(BaseRepo): up those resources. Attributes: - path: Path to the working copy (if it exists) or repository control directory (if the repository is bare) bare: Whether this is a bare repository @@ -1190,7 +1235,7 @@ def _write_reflog( @classmethod def discover(cls, start="."): - """Iterate parent directories to discover a repository + """Iterate parent directories to discover a repository. Return a Repo object for the first parent directory that looks like a Git repository. @@ -1323,15 +1368,18 @@ def stage(self, fs_paths: Union[str, bytes, os.PathLike, Iterable[Union[str, byt Args: fs_paths: List of paths, relative to the repository path """ - root_path_bytes = os.fsencode(self.path) if isinstance(fs_paths, (str, bytes, os.PathLike)): fs_paths = [fs_paths] fs_paths = list(fs_paths) - from .index import (_fs_to_tree_path, blob_from_path_and_stat, - index_entry_from_directory, index_entry_from_stat) + from .index import ( + _fs_to_tree_path, + blob_from_path_and_stat, + index_entry_from_directory, + index_entry_from_stat, + ) index = self.open_index() blob_normalizer = self.get_blob_normalizer() @@ -1376,10 +1424,10 @@ def stage(self, fs_paths: Union[str, bytes, os.PathLike, Iterable[Union[str, byt index.write() def unstage(self, fs_paths: List[str]): - """unstage specific file in the index + """Unstage specific file in the index Args: fs_paths: a list of files to unstage, - relative to the repository path + relative to the repository path. """ from .index import IndexEntry, _fs_to_tree_path @@ -1464,7 +1512,6 @@ def clone( symlinks: Symlinks setting (default to autodetect) Returns: Created repository as `Repo` """ - encoded_path = os.fsencode(self.path) if mkdir: @@ -1536,10 +1583,12 @@ def reset_index(self, tree: Optional[bytes] = None): Args: tree: Tree SHA to reset to, None for current HEAD tree. """ - from .index import (build_index_from_tree, - symlink, - validate_path_element_default, - validate_path_element_ntfs) + from .index import ( + build_index_from_tree, + symlink, + validate_path_element_default, + validate_path_element_ntfs, + ) if tree is None: head = self[b"HEAD"] @@ -1606,7 +1655,7 @@ def get_description(self): except FileNotFoundError: return None - def __repr__(self): + def __repr__(self) -> str: return "" % self.path def set_description(self, description): @@ -1615,7 +1664,6 @@ def set_description(self, description): Args: description: Text to set as description for this repository. """ - self._put_named_file("description", description) @classmethod @@ -1723,7 +1771,7 @@ def __exit__(self, exc_type, exc_val, exc_tb): self.close() def get_blob_normalizer(self): - """Return a BlobNormalizer object""" + """Return a BlobNormalizer object.""" # TODO Parse the git attributes files git_attributes = {} config_stack = self.get_config_stack() @@ -1746,7 +1794,7 @@ class MemoryRepo(BaseRepo): those have a stronger dependency on the filesystem. """ - def __init__(self): + def __init__(self) -> None: from .config import ConfigFile self._reflog = [] diff --git a/dulwich/server.py b/dulwich/server.py index 8d980d71e..01b167ce3 100644 --- a/dulwich/server.py +++ b/dulwich/server.py @@ -61,30 +61,61 @@ from dulwich import log_utils from .archive import tar_stream -from .errors import (ApplyDeltaError, ChecksumMismatch, GitProtocolError, - HookError, NotGitRepository, ObjectFormatException, - UnexpectedCommandError) +from .errors import ( + ApplyDeltaError, + ChecksumMismatch, + GitProtocolError, + HookError, + NotGitRepository, + ObjectFormatException, + UnexpectedCommandError, +) from .object_store import peel_sha from .objects import Commit, ObjectID, valid_hexsha -from .pack import (ObjectContainer, PackedObjectContainer, - write_pack_from_container) -from .protocol import (CAPABILITIES_REF, CAPABILITY_AGENT, - CAPABILITY_DELETE_REFS, CAPABILITY_INCLUDE_TAG, - CAPABILITY_MULTI_ACK, CAPABILITY_MULTI_ACK_DETAILED, - CAPABILITY_NO_DONE, CAPABILITY_NO_PROGRESS, - CAPABILITY_OFS_DELTA, CAPABILITY_QUIET, - CAPABILITY_REPORT_STATUS, CAPABILITY_SHALLOW, - CAPABILITY_SIDE_BAND_64K, CAPABILITY_THIN_PACK, - COMMAND_DEEPEN, COMMAND_DONE, COMMAND_HAVE, - COMMAND_SHALLOW, COMMAND_UNSHALLOW, COMMAND_WANT, - MULTI_ACK, MULTI_ACK_DETAILED, NAK_LINE, - SIDE_BAND_CHANNEL_DATA, SIDE_BAND_CHANNEL_FATAL, - SIDE_BAND_CHANNEL_PROGRESS, SINGLE_ACK, TCP_GIT_PORT, - ZERO_SHA, BufferedPktLineWriter, Protocol, - ReceivableProtocol, ack_type, capability_agent, - extract_capabilities, extract_want_line_capabilities, - format_ack_line, format_ref_line, format_shallow_line, - format_unshallow_line, symref_capabilities) +from .pack import ObjectContainer, PackedObjectContainer, write_pack_from_container +from .protocol import ( + CAPABILITIES_REF, + CAPABILITY_AGENT, + CAPABILITY_DELETE_REFS, + CAPABILITY_INCLUDE_TAG, + CAPABILITY_MULTI_ACK, + CAPABILITY_MULTI_ACK_DETAILED, + CAPABILITY_NO_DONE, + CAPABILITY_NO_PROGRESS, + CAPABILITY_OFS_DELTA, + CAPABILITY_QUIET, + CAPABILITY_REPORT_STATUS, + CAPABILITY_SHALLOW, + CAPABILITY_SIDE_BAND_64K, + CAPABILITY_THIN_PACK, + COMMAND_DEEPEN, + COMMAND_DONE, + COMMAND_HAVE, + COMMAND_SHALLOW, + COMMAND_UNSHALLOW, + COMMAND_WANT, + MULTI_ACK, + MULTI_ACK_DETAILED, + NAK_LINE, + SIDE_BAND_CHANNEL_DATA, + SIDE_BAND_CHANNEL_FATAL, + SIDE_BAND_CHANNEL_PROGRESS, + SINGLE_ACK, + TCP_GIT_PORT, + ZERO_SHA, + BufferedPktLineWriter, + Protocol, + ReceivableProtocol, + ack_type, + capability_agent, + extract_capabilities, + extract_want_line_capabilities, + format_ack_line, + format_ref_line, + format_shallow_line, + format_unshallow_line, + symref_capabilities, +) from .refs import PEELED_TAG_SUFFIX, RefsContainer, write_info_refs from .repo import BaseRepo, Repo @@ -117,8 +148,7 @@ class BackendRepo(TypingProtocol): refs: RefsContainer def get_refs(self) -> Dict[bytes, bytes]: - """ - Get all the refs in the repository + """Get all the refs in the repository. Returns: dict of name -> sha """ @@ -137,8 +167,7 @@ def get_peeled(self, name: bytes) -> Optional[bytes]: return None def find_missing_objects(self, determine_wants, graph_walker, progress, get_tagged=None): - """ - Yield the objects required for a list of commits. + """Yield the objects required for a list of commits. Args: progress: is a callback to send progress messages to the client @@ -151,7 +180,7 @@ def find_missing_objects(self, determine_wants, graph_walker, progress, get_tagg class DictBackend(Backend): """Trivial backend that looks up Git repositories in a dictionary.""" - def __init__(self, repos): + def __init__(self, repos) -> None: self.repos = repos def open_repository(self, path: str) -> BaseRepo: @@ -167,7 +196,7 @@ def open_repository(self, path: str) -> BaseRepo: class FileSystemBackend(Backend): """Simple backend looking up Git repositories in the local file system.""" - def __init__(self, root=os.sep): + def __init__(self, root=os.sep) -> None: super().__init__() self.root = (os.path.abspath(root) + os.sep).replace(os.sep * 2, os.sep) @@ -184,7 +213,7 @@ def open_repository(self, path): class Handler: """Smart protocol command handler base class.""" - def __init__(self, backend, proto, stateless_rpc=False): + def __init__(self, backend, proto, stateless_rpc=False) -> None: self.backend = backend self.proto = proto self.stateless_rpc = stateless_rpc @@ -196,7 +225,7 @@ def handle(self): class PackHandler(Handler): """Protocol handler for packs.""" - def __init__(self, backend, proto, stateless_rpc=False): + def __init__(self, backend, proto, stateless_rpc=False) -> None: super().__init__(backend, proto, stateless_rpc) self._client_capabilities = None # Flags needed for the no-done capability @@ -253,7 +282,7 @@ def notify_done(self) -> None: class UploadPackHandler(PackHandler): """Protocol handler for uploading a pack to the client.""" - def __init__(self, backend, args, proto, stateless_rpc=False, advertise_refs=False): + def __init__(self, backend, args, proto, stateless_rpc=False, advertise_refs=False) -> None: super().__init__( backend, proto, stateless_rpc=stateless_rpc ) @@ -528,7 +557,7 @@ class _ProtocolGraphWalker: any calls to next() or ack() are made. """ - def __init__(self, handler, object_store: ObjectContainer, get_peeled, get_symrefs): + def __init__(self, handler, object_store: ObjectContainer, get_peeled, get_symrefs) -> None: self.handler = handler self.store: ObjectContainer = object_store self.get_peeled = get_peeled @@ -660,6 +689,7 @@ def read_proto_line(self, allowed): Args: allowed: An iterable of command names that should be allowed. Returns: A tuple of (command, value); see _split_proto_line. + Raises: UnexpectedCommandError: If an error occurred reading the line. """ @@ -731,7 +761,7 @@ def set_ack_type(self, ack_type): class SingleAckGraphWalkerImpl: """Graph walker implementation that speaks the single-ack protocol.""" - def __init__(self, walker): + def __init__(self, walker) -> None: self.walker = walker self._common = [] @@ -775,7 +805,7 @@ def handle_done(self, done_required, done_received): class MultiAckGraphWalkerImpl: """Graph walker implementation that speaks the multi-ack protocol.""" - def __init__(self, walker): + def __init__(self, walker) -> None: self.walker = walker self._found_base = False self._common = [] @@ -834,7 +864,7 @@ def handle_done(self, done_required, done_received): class MultiAckDetailedGraphWalkerImpl: """Graph walker implementation speaking the multi-ack-detailed protocol.""" - def __init__(self, walker): + def __init__(self, walker) -> None: self.walker = walker self._common = [] @@ -899,7 +929,7 @@ def handle_done(self, done_required, done_received): class ReceivePackHandler(PackHandler): """Protocol handler for downloading a pack from the client.""" - def __init__(self, backend, args, proto, stateless_rpc=False, advertise_refs=False): + def __init__(self, backend, args, proto, stateless_rpc=False, advertise_refs=False) -> None: super().__init__( backend, proto, stateless_rpc=stateless_rpc ) @@ -1063,7 +1093,7 @@ def handle(self) -> None: class UploadArchiveHandler(Handler): - def __init__(self, backend, args, proto, stateless_rpc=False): + def __init__(self, backend, args, proto, stateless_rpc=False) -> None: super().__init__(backend, proto, stateless_rpc) self.repo = backend.open_repository(args[0]) @@ -1111,7 +1141,7 @@ def write(x): class TCPGitRequestHandler(socketserver.StreamRequestHandler): - def __init__(self, handlers, *args, **kwargs): + def __init__(self, handlers, *args, **kwargs) -> None: self.handlers = handlers socketserver.StreamRequestHandler.__init__(self, *args, **kwargs) @@ -1135,7 +1165,7 @@ class TCPGitServer(socketserver.TCPServer): def _make_handler(self, *args, **kwargs): return TCPGitRequestHandler(self.handlers, *args, **kwargs) - def __init__(self, backend, listen_addr, port=TCP_GIT_PORT, handlers=None): + def __init__(self, backend, listen_addr, port=TCP_GIT_PORT, handlers=None) -> None: self.handlers = dict(DEFAULT_HANDLERS) if handlers is not None: self.handlers.update(handlers) diff --git a/dulwich/stash.py b/dulwich/stash.py index fb8d824f6..0bb6f9fb9 100644 --- a/dulwich/stash.py +++ b/dulwich/stash.py @@ -36,7 +36,7 @@ class Stash: Note that this doesn't currently update the working tree. """ - def __init__(self, repo, ref=DEFAULT_STASH_REF): + def __init__(self, repo, ref=DEFAULT_STASH_REF) -> None: self._ref = ref self._repo = repo @@ -128,5 +128,5 @@ def push(self, committer=None, author=None, message=None): def __getitem__(self, index): return list(self.stashes())[index] - def __len__(self): + def __len__(self) -> int: return len(list(self.stashes())) diff --git a/dulwich/submodule.py b/dulwich/submodule.py index c7137ac2d..895c34081 100644 --- a/dulwich/submodule.py +++ b/dulwich/submodule.py @@ -18,8 +18,7 @@ # License, Version 2.0. # -"""Working with Git submodules. -""" +"""Working with Git submodules.""" from typing import Iterator, Tuple @@ -28,7 +27,7 @@ def iter_cached_submodules(store, root_tree_id: bytes) -> Iterator[Tuple[str, bytes]]: - """iterate over cached submodules. + """Iterate over cached submodules. Args: store: Object store to iterate diff --git a/dulwich/tests/__init__.py b/dulwich/tests/__init__.py index c3f3a9d30..fbe316f8d 100644 --- a/dulwich/tests/__init__.py +++ b/dulwich/tests/__init__.py @@ -34,11 +34,11 @@ import subprocess import sys import tempfile + # If Python itself provides an exception, use that import unittest -from unittest import SkipTest +from unittest import SkipTest, expectedFailure, skipIf from unittest import TestCase as _TestCase # noqa: F401 -from unittest import expectedFailure, skipIf class TestCase(_TestCase): diff --git a/dulwich/tests/compat/server_utils.py b/dulwich/tests/compat/server_utils.py index abc677726..2459f1bcf 100644 --- a/dulwich/tests/compat/server_utils.py +++ b/dulwich/tests/compat/server_utils.py @@ -37,7 +37,7 @@ class _StubRepo: """A stub repo that just contains a path to tear down.""" - def __init__(self, name): + def __init__(self, name) -> None: temp_dir = tempfile.mkdtemp() self.path = os.path.join(temp_dir, name) os.mkdir(self.path) diff --git a/dulwich/tests/compat/test_client.py b/dulwich/tests/compat/test_client.py index e811f7bf5..e817b4bb0 100644 --- a/dulwich/tests/compat/test_client.py +++ b/dulwich/tests/compat/test_client.py @@ -38,8 +38,14 @@ from dulwich import client, file, index, objects, protocol, repo from dulwich.tests import SkipTest, expectedFailure -from .utils import (_DEFAULT_GIT, CompatTestCase, check_for_daemon, - import_repo_to_dir, rmtree_ro, run_git_or_fail) +from .utils import ( + _DEFAULT_GIT, + CompatTestCase, + check_for_daemon, + import_repo_to_dir, + rmtree_ro, + run_git_or_fail, +) if sys.platform == "win32": import ctypes @@ -621,7 +627,7 @@ class HTTPGitServer(http.server.HTTPServer): allow_reuse_address = True - def __init__(self, server_address, root_path): + def __init__(self, server_address, root_path) -> None: http.server.HTTPServer.__init__(self, server_address, GitHTTPRequestHandler) self.root_path = root_path self.server_name = "localhost" diff --git a/dulwich/tests/compat/test_repository.py b/dulwich/tests/compat/test_repository.py index fac2c1c77..f1390fdb9 100644 --- a/dulwich/tests/compat/test_repository.py +++ b/dulwich/tests/compat/test_repository.py @@ -28,8 +28,7 @@ from ...objects import hex_to_sha from ...repo import Repo, check_ref_format -from .utils import (CompatTestCase, require_git_version, rmtree_ro, - run_git_or_fail) +from .utils import CompatTestCase, require_git_version, rmtree_ro, run_git_or_fail class ObjectStoreTestCase(CompatTestCase): diff --git a/dulwich/tests/compat/test_web.py b/dulwich/tests/compat/test_web.py index 4001ec270..ff53f642b 100644 --- a/dulwich/tests/compat/test_web.py +++ b/dulwich/tests/compat/test_web.py @@ -33,8 +33,12 @@ from dulwich.tests import SkipTest, skipIf from ...server import DictBackend, ReceivePackHandler, UploadPackHandler -from ...web import (HTTPGitApplication, WSGIRequestHandlerLogger, - WSGIServerLogger, make_wsgi_chain) +from ...web import ( + HTTPGitApplication, + WSGIRequestHandlerLogger, + WSGIServerLogger, + make_wsgi_chain, +) from .server_utils import NoSideBand64kReceivePackHandler, ServerTests from .utils import CompatTestCase diff --git a/dulwich/tests/compat/utils.py b/dulwich/tests/compat/utils.py index b6a13c69d..ed2260dec 100644 --- a/dulwich/tests/compat/utils.py +++ b/dulwich/tests/compat/utils.py @@ -84,6 +84,7 @@ def require_git_version(required_version, git_path=_DEFAULT_GIT): sub-point); omitted components default to 0. git_path: Path to the git executable; defaults to the version in the system path. + Raises: ValueError: if the required version tuple has too many parts. SkipTest: if no suitable git version was found at the given path. @@ -132,10 +133,10 @@ def run_git( Returns: A tuple of (returncode, stdout contents, stderr contents). If capture_stdout is False, None will be returned as stdout contents. If capture_stderr is False, None will be returned as stderr contents. + Raises: OSError: if the git executable was not found. """ - env = popen_kwargs.pop("env", {}) env["LC_ALL"] = env["LANG"] = "C" env["PATH"] = os.getenv("PATH") diff --git a/dulwich/tests/test_client.py b/dulwich/tests/test_client.py index 8886d44af..7bd3617b3 100644 --- a/dulwich/tests/test_client.py +++ b/dulwich/tests/test_client.py @@ -33,15 +33,29 @@ from dulwich import client from dulwich.tests import TestCase, skipIf -from ..client import (FetchPackResult, GitProtocolError, HangupException, - HttpGitClient, InvalidWants, LocalGitClient, - PLinkSSHVendor, ReportStatusParser, SendPackError, - SSHGitClient, StrangeHostname, SubprocessSSHVendor, - TCPGitClient, TraditionalGitClient, - _remote_error_from_stderr, check_wants, - default_urllib3_manager, get_credentials_from_store, - get_transport_and_path, get_transport_and_path_from_url, - parse_rsync_url) +from ..client import ( + FetchPackResult, + GitProtocolError, + HangupException, + HttpGitClient, + InvalidWants, + LocalGitClient, + PLinkSSHVendor, + ReportStatusParser, + SendPackError, + SSHGitClient, + StrangeHostname, + SubprocessSSHVendor, + TCPGitClient, + TraditionalGitClient, + _remote_error_from_stderr, + check_wants, + default_urllib3_manager, + get_credentials_from_store, + get_transport_and_path, + get_transport_and_path_from_url, + parse_rsync_url, +) from ..config import ConfigDict from ..objects import Commit, Tree from ..pack import pack_objects_to_data, write_pack_data, write_pack_objects @@ -51,7 +65,7 @@ class DummyClient(TraditionalGitClient): - def __init__(self, can_read, read, write): + def __init__(self, can_read, read, write) -> None: self.can_read = can_read self.read = read self.write = write @@ -62,7 +76,7 @@ def _connect(self, service, path): class DummyPopen: - def __init__(self, *args, **kwards): + def __init__(self, *args, **kwards) -> None: self.stdin = BytesIO(b"stdin") self.stdout = BytesIO(b"stdout") self.stderr = BytesIO(b"stderr") @@ -680,7 +694,7 @@ def test_file_win(self): class TestSSHVendor: - def __init__(self): + def __init__(self) -> None: self.host = None self.command = "" self.username = None @@ -1075,7 +1089,7 @@ def test_url_redirect_location(self): # we need to mock urllib3.PoolManager as this test will fail # otherwise without an active internet connection class PoolManagerMock: - def __init__(self): + def __init__(self) -> None: self.headers = {} def request(self, method, url, fields=None, headers=None, redirect=True, preload_content=True): diff --git a/dulwich/tests/test_config.py b/dulwich/tests/test_config.py index 01a534275..bae048eb8 100644 --- a/dulwich/tests/test_config.py +++ b/dulwich/tests/test_config.py @@ -28,10 +28,18 @@ from dulwich.tests import TestCase -from ..config import (ConfigDict, ConfigFile, StackedConfig, - _check_section_name, _check_variable_name, _escape_value, - _format_string, _parse_string, apply_instead_of, - parse_submodules) +from ..config import ( + ConfigDict, + ConfigFile, + StackedConfig, + _check_section_name, + _check_variable_name, + _escape_value, + _format_string, + _parse_string, + apply_instead_of, + parse_submodules, +) class ConfigFileTests(TestCase): diff --git a/dulwich/tests/test_credentials.py b/dulwich/tests/test_credentials.py index 7910900b5..fb183bafd 100644 --- a/dulwich/tests/test_credentials.py +++ b/dulwich/tests/test_credentials.py @@ -24,8 +24,7 @@ from dulwich.tests import TestCase from ..config import ConfigDict -from ..credentials import (match_partial_url, match_urls, - urlmatch_credential_sections) +from ..credentials import match_partial_url, match_urls, urlmatch_credential_sections class TestCredentialHelpersUtils(TestCase): diff --git a/dulwich/tests/test_diff_tree.py b/dulwich/tests/test_diff_tree.py index 16cdd7a74..63dc8fcd4 100644 --- a/dulwich/tests/test_diff_tree.py +++ b/dulwich/tests/test_diff_tree.py @@ -24,12 +24,24 @@ from dulwich.tests import TestCase -from ..diff_tree import (CHANGE_COPY, CHANGE_MODIFY, CHANGE_RENAME, - CHANGE_UNCHANGED, RenameDetector, TreeChange, - _count_blocks, _count_blocks_py, _is_tree, - _is_tree_py, _merge_entries, _merge_entries_py, - _similarity_score, _tree_change_key, tree_changes, - tree_changes_for_merge) +from ..diff_tree import ( + CHANGE_COPY, + CHANGE_MODIFY, + CHANGE_RENAME, + CHANGE_UNCHANGED, + RenameDetector, + TreeChange, + _count_blocks, + _count_blocks_py, + _is_tree, + _is_tree_py, + _merge_entries, + _merge_entries_py, + _similarity_score, + _tree_change_key, + tree_changes, + tree_changes_for_merge, +) from ..index import commit_tree from ..object_store import MemoryObjectStore from ..objects import Blob, ShaFile, Tree, TreeEntry diff --git a/dulwich/tests/test_ignore.py b/dulwich/tests/test_ignore.py index dbd1f2ced..24f0dcb1d 100644 --- a/dulwich/tests/test_ignore.py +++ b/dulwich/tests/test_ignore.py @@ -28,8 +28,15 @@ from dulwich.tests import TestCase -from ..ignore import (IgnoreFilter, IgnoreFilterManager, IgnoreFilterStack, - Pattern, match_pattern, read_ignore_patterns, translate) +from ..ignore import ( + IgnoreFilter, + IgnoreFilterManager, + IgnoreFilterStack, + Pattern, + match_pattern, + read_ignore_patterns, + translate, +) from ..repo import Repo POSITIVE_MATCH_TESTS = [ diff --git a/dulwich/tests/test_index.py b/dulwich/tests/test_index.py index d94a01081..36a3fe2cf 100644 --- a/dulwich/tests/test_index.py +++ b/dulwich/tests/test_index.py @@ -32,12 +32,24 @@ from dulwich.tests import TestCase, skipIf -from ..index import (Index, IndexEntry, _fs_to_tree_path, _tree_to_fs_path, - build_index_from_tree, cleanup_mode, commit_tree, - get_unstaged_changes, index_entry_from_stat, read_index, - read_index_dict, validate_path_element_default, - validate_path_element_ntfs, write_cache_time, write_index, - write_index_dict) +from ..index import ( + Index, + IndexEntry, + _fs_to_tree_path, + _tree_to_fs_path, + build_index_from_tree, + cleanup_mode, + commit_tree, + get_unstaged_changes, + index_entry_from_stat, + read_index, + read_index_dict, + validate_path_element_default, + validate_path_element_ntfs, + write_cache_time, + write_index, + write_index_dict, +) from ..object_store import MemoryObjectStore from ..objects import S_IFGITLINK, Blob, Commit, Tree from ..repo import Repo @@ -643,7 +655,6 @@ def test_git_submodule_exists(self): class GetUnstagedChangesTests(TestCase): def test_get_unstaged_changes(self): """Unit test for get_unstaged_changes.""" - repo_dir = tempfile.mkdtemp() self.addCleanup(shutil.rmtree, repo_dir) with Repo.init(repo_dir) as repo: @@ -676,7 +687,6 @@ def test_get_unstaged_changes(self): def test_get_unstaged_deleted_changes(self): """Unit test for get_unstaged_changes.""" - repo_dir = tempfile.mkdtemp() self.addCleanup(shutil.rmtree, repo_dir) with Repo.init(repo_dir) as repo: @@ -701,7 +711,6 @@ def test_get_unstaged_deleted_changes(self): def test_get_unstaged_changes_removed_replaced_by_directory(self): """Unit test for get_unstaged_changes.""" - repo_dir = tempfile.mkdtemp() self.addCleanup(shutil.rmtree, repo_dir) with Repo.init(repo_dir) as repo: @@ -728,7 +737,6 @@ def test_get_unstaged_changes_removed_replaced_by_directory(self): @skipIf(not can_symlink(), "Requires symlink support") def test_get_unstaged_changes_removed_replaced_by_link(self): """Unit test for get_unstaged_changes.""" - repo_dir = tempfile.mkdtemp() self.addCleanup(shutil.rmtree, repo_dir) with Repo.init(repo_dir) as repo: diff --git a/dulwich/tests/test_line_ending.py b/dulwich/tests/test_line_ending.py index 49d95d817..f0f406033 100644 --- a/dulwich/tests/test_line_ending.py +++ b/dulwich/tests/test_line_ending.py @@ -23,14 +23,18 @@ from dulwich.tests import TestCase -from ..line_ending import (convert_crlf_to_lf, convert_lf_to_crlf, - get_checkin_filter_autocrlf, - get_checkout_filter_autocrlf, normalize_blob) +from ..line_ending import ( + convert_crlf_to_lf, + convert_lf_to_crlf, + get_checkin_filter_autocrlf, + get_checkout_filter_autocrlf, + normalize_blob, +) from ..objects import Blob class LineEndingConversion(TestCase): - """Test the line ending conversion functions in various cases""" + """Test the line ending conversion functions in various cases.""" def test_convert_crlf_to_lf_no_op(self): self.assertEqual(convert_crlf_to_lf(b"foobar"), b"foobar") diff --git a/dulwich/tests/test_lru_cache.py b/dulwich/tests/test_lru_cache.py index 14551efcb..d15b15d50 100644 --- a/dulwich/tests/test_lru_cache.py +++ b/dulwich/tests/test_lru_cache.py @@ -354,7 +354,7 @@ def cleanup(key, value): self.assertEqual([("test", "key that is too big")], cleanup_calls) def test_adding_clears_cache_based_on_size(self): - """The cache is cleared in LRU order until small enough""" + """The cache is cleared in LRU order until small enough.""" cache = lru_cache.LRUSizeCache(max_size=20) cache.add("key1", "value") # 5 chars cache.add("key2", "value2") # 6 chars diff --git a/dulwich/tests/test_missing_obj_finder.py b/dulwich/tests/test_missing_obj_finder.py index 5423b18b0..dde286231 100644 --- a/dulwich/tests/test_missing_obj_finder.py +++ b/dulwich/tests/test_missing_obj_finder.py @@ -96,14 +96,14 @@ def test_1_to_3(self): self.assertMissingMatch([self.cmt(1).id], [self.cmt(3).id], self.missing_1_3) def test_bogus_haves(self): - """Ensure non-existent SHA in haves are tolerated""" + """Ensure non-existent SHA in haves are tolerated.""" bogus_sha = self.cmt(2).id[::-1] haves = [self.cmt(1).id, bogus_sha] wants = [self.cmt(3).id] self.assertMissingMatch(haves, wants, self.missing_1_3) def test_bogus_wants_failure(self): - """Ensure non-existent SHA in wants are not tolerated""" + """Ensure non-existent SHA in wants are not tolerated.""" bogus_sha = self.cmt(2).id[::-1] haves = [self.cmt(1).id] wants = [self.cmt(3).id, bogus_sha] diff --git a/dulwich/tests/test_object_store.py b/dulwich/tests/test_object_store.py index b65463ed8..a2278b513 100644 --- a/dulwich/tests/test_object_store.py +++ b/dulwich/tests/test_object_store.py @@ -34,12 +34,26 @@ from ..errors import NotTreeError from ..index import commit_tree -from ..object_store import (DiskObjectStore, MemoryObjectStore, - ObjectStoreGraphWalker, OverlayObjectStore, - commit_tree_changes, iter_tree_contents, peel_sha, - read_packs_file, tree_lookup_path) -from ..objects import (S_IFGITLINK, Blob, EmptyFileException, - SubmoduleEncountered, Tree, TreeEntry, sha_to_hex) +from ..object_store import ( + DiskObjectStore, + MemoryObjectStore, + ObjectStoreGraphWalker, + OverlayObjectStore, + commit_tree_changes, + iter_tree_contents, + peel_sha, + read_packs_file, + tree_lookup_path, +) +from ..objects import ( + S_IFGITLINK, + Blob, + EmptyFileException, + SubmoduleEncountered, + Tree, + TreeEntry, + sha_to_hex, +) from ..pack import REF_DELTA, write_pack_objects from ..protocol import DEPTH_INFINITE from .utils import build_pack, make_object, make_tag @@ -427,7 +441,7 @@ def test_file_modes(self): self.assertEqual(oct(mode), packmode) def test_corrupted_object_raise_exception(self): - """Corrupted sha1 disk file should raise specific exception""" + """Corrupted sha1 disk file should raise specific exception.""" self.store.add_object(testobject) self.assertEqual( (Blob.type_num, b"yummy data"), self.store.get_raw(testobject.id) diff --git a/dulwich/tests/test_objects.py b/dulwich/tests/test_objects.py index 5b189fb92..0334e8d03 100644 --- a/dulwich/tests/test_objects.py +++ b/dulwich/tests/test_objects.py @@ -33,13 +33,29 @@ from dulwich.tests import TestCase from ..errors import ObjectFormatException -from ..objects import (MAX_TIME, Blob, Commit, ShaFile, Tag, Tree, TreeEntry, - _parse_tree_py, _sorted_tree_items_py, check_hexsha, - check_identity, format_timezone, hex_to_filename, - hex_to_sha, object_class, parse_timezone, parse_tree, - pretty_format_tree_entry, sha_to_hex, sorted_tree_items) -from .utils import (ext_functest_builder, functest_builder, make_commit, - make_object) +from ..objects import ( + MAX_TIME, + Blob, + Commit, + ShaFile, + Tag, + Tree, + TreeEntry, + _parse_tree_py, + _sorted_tree_items_py, + check_hexsha, + check_identity, + format_timezone, + hex_to_filename, + hex_to_sha, + object_class, + parse_timezone, + parse_tree, + pretty_format_tree_entry, + sha_to_hex, + sorted_tree_items, +) +from .utils import ext_functest_builder, functest_builder, make_commit, make_object a_sha = b"6f670c0fb53f9463760b7295fbb814e965fb20c8" b_sha = b"2969be3e8ee1c0222396a5611407e4769f14e54b" @@ -57,14 +73,14 @@ def test_reverse(self): class BlobReadTests(TestCase): - """Test decompression of blobs""" + """Test decompression of blobs.""" def get_sha_file(self, cls, base, sha): dir = os.path.join(os.path.dirname(__file__), "..", "..", "testdata", base) return cls.from_path(hex_to_filename(dir, sha)) def get_blob(self, sha): - """Return the blob named sha from the test data dir""" + """Return the blob named sha from the test data dir.""" return self.get_sha_file(Blob, "blobs", sha) def get_tree(self, sha): @@ -665,7 +681,7 @@ def test_check_commit_with_unparseable_time(self): ) def test_check_commit_with_overflow_date(self): - """Date with overflow should raise an ObjectFormatException when checked""" + """Date with overflow should raise an ObjectFormatException when checked.""" identity_with_wrong_time = ( b"Igor Sysoev 18446743887488505614 +42707004" ) @@ -686,7 +702,7 @@ def test_check_commit_with_overflow_date(self): commit.check() def test_mangled_author_line(self): - """Mangled author line should successfully parse""" + """Mangled author line should successfully parse.""" author_line = ( b'Karl MacMillan <"Karl MacMillan ' b'"> 1197475547 -0500' @@ -1116,7 +1132,7 @@ def test_check_tag_with_unparseable_field(self): ) def test_check_tag_with_overflow_time(self): - """Date with overflow should raise an ObjectFormatException when checked""" + """Date with overflow should raise an ObjectFormatException when checked.""" author = "Some Dude {} +0000".format(MAX_TIME + 1) tag = Tag.from_string(self.make_tag_text(tagger=(author.encode()))) with self.assertRaises(ObjectFormatException): diff --git a/dulwich/tests/test_objectspec.py b/dulwich/tests/test_objectspec.py index 586682bb2..eca8007a6 100644 --- a/dulwich/tests/test_objectspec.py +++ b/dulwich/tests/test_objectspec.py @@ -26,9 +26,16 @@ from dulwich.tests import TestCase from ..objects import Blob -from ..objectspec import (parse_commit, parse_commit_range, parse_object, - parse_ref, parse_refs, parse_reftuple, - parse_reftuples, parse_tree) +from ..objectspec import ( + parse_commit, + parse_commit_range, + parse_object, + parse_ref, + parse_refs, + parse_reftuple, + parse_reftuples, + parse_tree, +) from ..repo import MemoryRepo from .utils import build_commit_graph diff --git a/dulwich/tests/test_pack.py b/dulwich/tests/test_pack.py index 2b50dd02b..90c2c5157 100644 --- a/dulwich/tests/test_pack.py +++ b/dulwich/tests/test_pack.py @@ -36,13 +36,30 @@ from ..file import GitFile from ..object_store import MemoryObjectStore from ..objects import Blob, Commit, Tree, hex_to_sha, sha_to_hex -from ..pack import (OFS_DELTA, REF_DELTA, DeltaChainIterator, MemoryPackIndex, - Pack, PackData, PackStreamReader, UnpackedObject, - _delta_encode_size, _encode_copy_operation, apply_delta, - compute_file_sha, create_delta, deltify_pack_objects, - load_pack_index, read_zlib_chunks, unpack_object, - write_pack, write_pack_header, write_pack_index_v1, - write_pack_index_v2, write_pack_object) +from ..pack import ( + OFS_DELTA, + REF_DELTA, + DeltaChainIterator, + MemoryPackIndex, + Pack, + PackData, + PackStreamReader, + UnpackedObject, + _delta_encode_size, + _encode_copy_operation, + apply_delta, + compute_file_sha, + create_delta, + deltify_pack_objects, + load_pack_index, + read_zlib_chunks, + unpack_object, + write_pack, + write_pack_header, + write_pack_index_v1, + write_pack_index_v2, + write_pack_object, +) from .utils import build_pack, make_object pack1_sha = b"bc63ddad95e7321ee734ea11a7a62d314e0d7481" @@ -54,7 +71,7 @@ class PackTests(TestCase): - """Base class for testing packs""" + """Base class for testing packs.""" def setUp(self): super().setUp() @@ -64,13 +81,13 @@ def setUp(self): datadir = os.path.abspath(os.path.join(os.path.dirname(__file__), "../../testdata/packs")) def get_pack_index(self, sha): - """Returns a PackIndex from the datadir with the given sha""" + """Returns a PackIndex from the datadir with the given sha.""" return load_pack_index( os.path.join(self.datadir, "pack-%s.idx" % sha.decode("ascii")) ) def get_pack_data(self, sha): - """Returns a PackData object from the datadir with the given sha""" + """Returns a PackData object from the datadir with the given sha.""" return PackData( os.path.join(self.datadir, "pack-%s.pack" % sha.decode("ascii")) ) @@ -86,7 +103,7 @@ def assertSucceeds(self, func, *args, **kwargs): class PackIndexTests(PackTests): - """Class that tests the index of packfiles""" + """Class that tests the index of packfiles.""" def test_object_offset(self): """Tests that the correct object offset is returned from the index.""" @@ -377,7 +394,7 @@ def test_pack_tuples(self): self.assertEqual(3, len(tuples)) def test_get_object_at(self): - """Tests random access for non-delta objects""" + """Tests random access for non-delta objects.""" with self.get_pack(pack1_sha) as p: obj = p[a_sha] self.assertEqual(obj.type_name, b"blob") @@ -924,7 +941,7 @@ class TestPackIterator(DeltaChainIterator): _compute_crc32 = True - def __init__(self, *args, **kwargs): + def __init__(self, *args, **kwargs) -> None: super().__init__(*args, **kwargs) self._unpacked_offsets = set() diff --git a/dulwich/tests/test_patch.py b/dulwich/tests/test_patch.py index f9b685a02..3653f7fbb 100644 --- a/dulwich/tests/test_patch.py +++ b/dulwich/tests/test_patch.py @@ -26,8 +26,14 @@ from ..object_store import MemoryObjectStore from ..objects import S_IFGITLINK, Blob, Commit, Tree -from ..patch import (get_summary, git_am_patch_split, write_blob_diff, - write_commit_patch, write_object_diff, write_tree_diff) +from ..patch import ( + get_summary, + git_am_patch_split, + write_blob_diff, + write_commit_patch, + write_object_diff, + write_tree_diff, +) class WriteCommitPatchTests(TestCase): diff --git a/dulwich/tests/test_porcelain.py b/dulwich/tests/test_porcelain.py index a020b22bd..c6d4ec204 100644 --- a/dulwich/tests/test_porcelain.py +++ b/dulwich/tests/test_porcelain.py @@ -592,7 +592,7 @@ def test_no_envs(self): class CleanTests(PorcelainTestCase): def put_files(self, tracked, ignored, untracked, empty_dirs): - """Put the described files in the wd""" + """Put the described files in the wd.""" all_files = tracked | ignored | untracked for file_path in all_files: abs_path = os.path.join(self.repo.path, file_path) @@ -617,7 +617,7 @@ def put_files(self, tracked, ignored, untracked, empty_dirs): porcelain.commit(repo=self.repo.path, message="init commit") def assert_wd(self, expected_paths): - """Assert paths of files and dirs in wd are same as expected_paths""" + """Assert paths of files and dirs in wd are same as expected_paths.""" control_dir_rel = os.path.relpath(self.repo._controldir, self.repo.path) # normalize paths to simplify comparison across platforms @@ -1981,8 +1981,7 @@ def test_init(self): class PushTests(PorcelainTestCase): def test_simple(self): - """ - Basic test of porcelain push where self.repo is the remote. First + """Basic test of porcelain push where self.repo is the remote. First clone the remote, commit a file to the clone, then push the changes back to the remote. """ @@ -2392,7 +2391,6 @@ def test_empty(self): def test_status_base(self): """Integration test for `status` functionality.""" - # Commit a dummy file then modify it fullpath = os.path.join(self.repo.path, "foo") with open(fullpath, "w") as f: @@ -2561,7 +2559,6 @@ def test_status_autocrlf_input(self): def test_get_tree_changes_add(self): """Unit test for get_tree_changes add.""" - # Make a dummy file, stage filename = "bar" fullpath = os.path.join(self.repo.path, filename) @@ -2589,7 +2586,6 @@ def test_get_tree_changes_add(self): def test_get_tree_changes_modify(self): """Unit test for get_tree_changes modify.""" - # Make a dummy file, stage, commit, modify filename = "foo" fullpath = os.path.join(self.repo.path, filename) @@ -2614,7 +2610,6 @@ def test_get_tree_changes_modify(self): def test_get_tree_changes_delete(self): """Unit test for get_tree_changes delete.""" - # Make a dummy file, stage, commit, remove filename = "foo" fullpath = os.path.join(self.repo.path, filename) diff --git a/dulwich/tests/test_protocol.py b/dulwich/tests/test_protocol.py index a586fe67f..e20391937 100644 --- a/dulwich/tests/test_protocol.py +++ b/dulwich/tests/test_protocol.py @@ -26,10 +26,19 @@ from dulwich.tests import TestCase from ..errors import HangupException -from ..protocol import (MULTI_ACK, MULTI_ACK_DETAILED, SINGLE_ACK, - BufferedPktLineWriter, GitProtocolError, PktLineParser, - Protocol, ReceivableProtocol, ack_type, - extract_capabilities, extract_want_line_capabilities) +from ..protocol import ( + MULTI_ACK, + MULTI_ACK_DETAILED, + SINGLE_ACK, + BufferedPktLineWriter, + GitProtocolError, + PktLineParser, + Protocol, + ReceivableProtocol, + ack_type, + extract_capabilities, + extract_want_line_capabilities, +) class BaseProtocolTests: @@ -109,7 +118,7 @@ def setUp(self): class ReceivableBytesIO(BytesIO): """BytesIO with socket-like recv semantics for testing.""" - def __init__(self): + def __init__(self) -> None: BytesIO.__init__(self) self.allow_read_past_eof = False diff --git a/dulwich/tests/test_reflog.py b/dulwich/tests/test_reflog.py index b15b381b3..fd0e7d33f 100644 --- a/dulwich/tests/test_reflog.py +++ b/dulwich/tests/test_reflog.py @@ -25,8 +25,12 @@ from dulwich.tests import TestCase from ..objects import ZERO_SHA -from ..reflog import (drop_reflog_entry, format_reflog_line, parse_reflog_line, - read_reflog) +from ..reflog import ( + drop_reflog_entry, + format_reflog_line, + parse_reflog_line, + read_reflog, +) class ReflogLineTests(TestCase): diff --git a/dulwich/tests/test_refs.py b/dulwich/tests/test_refs.py index 7abff718e..44f5616b7 100644 --- a/dulwich/tests/test_refs.py +++ b/dulwich/tests/test_refs.py @@ -30,10 +30,18 @@ from ..file import GitFile from ..objects import ZERO_SHA -from ..refs import (DictRefsContainer, InfoRefsContainer, SymrefLoop, - _split_ref_line, check_ref_format, parse_symref_value, - read_packed_refs, read_packed_refs_with_peeled, - strip_peeled_refs, write_packed_refs) +from ..refs import ( + DictRefsContainer, + InfoRefsContainer, + SymrefLoop, + _split_ref_line, + check_ref_format, + parse_symref_value, + read_packed_refs, + read_packed_refs_with_peeled, + strip_peeled_refs, + write_packed_refs, +) from ..repo import Repo from .utils import open_repo, tear_down_repo diff --git a/dulwich/tests/test_repository.py b/dulwich/tests/test_repository.py index 8d84b605b..60d318384 100644 --- a/dulwich/tests/test_repository.py +++ b/dulwich/tests/test_repository.py @@ -35,9 +35,14 @@ from ..config import Config from ..errors import NotGitRepository from ..object_store import tree_lookup_path -from ..repo import (InvalidUserIdentity, MemoryRepo, Repo, - UnsupportedExtension, UnsupportedVersion, - check_user_identity) +from ..repo import ( + InvalidUserIdentity, + MemoryRepo, + Repo, + UnsupportedExtension, + UnsupportedVersion, + check_user_identity, +) from .utils import open_repo, setup_warning_catcher, tear_down_repo missing_sha = b"b91fa4d900e17e99b433218e988c4eb4a3e9a097" @@ -565,13 +570,11 @@ def test_get_config_stack(self): self.assertIsInstance(r.get_config_stack(), Config) def test_common_revisions(self): - """ - This test demonstrates that ``find_common_revisions()`` actually + """This test demonstrates that ``find_common_revisions()`` actually returns common heads, not revisions; dulwich already uses ``find_common_revisions()`` in such a manner (see ``Repo.find_objects()``). """ - expected_shas = {b"60dacdc733de308bb77bb76ce0fb0f9b44c9769e"} # Source for objects. diff --git a/dulwich/tests/test_server.py b/dulwich/tests/test_server.py index ea76e7666..f54247413 100644 --- a/dulwich/tests/test_server.py +++ b/dulwich/tests/test_server.py @@ -28,18 +28,32 @@ from dulwich.tests import TestCase -from ..errors import (GitProtocolError, HangupException, NotGitRepository, - UnexpectedCommandError) +from ..errors import ( + GitProtocolError, + HangupException, + NotGitRepository, + UnexpectedCommandError, +) from ..object_store import MemoryObjectStore from ..objects import Tree from ..protocol import ZERO_SHA, format_capability_line from ..repo import MemoryRepo, Repo -from ..server import (Backend, DictBackend, FileSystemBackend, - MultiAckDetailedGraphWalkerImpl, MultiAckGraphWalkerImpl, - PackHandler, ReceivePackHandler, - SingleAckGraphWalkerImpl, UploadPackHandler, - _find_shallow, _ProtocolGraphWalker, _split_proto_line, - serve_command, update_server_info) +from ..server import ( + Backend, + DictBackend, + FileSystemBackend, + MultiAckDetailedGraphWalkerImpl, + MultiAckGraphWalkerImpl, + PackHandler, + ReceivePackHandler, + SingleAckGraphWalkerImpl, + UploadPackHandler, + _find_shallow, + _ProtocolGraphWalker, + _split_proto_line, + serve_command, + update_server_info, +) from .utils import make_commit, make_tag ONE = b"1" * 40 @@ -51,7 +65,7 @@ class TestProto: - def __init__(self): + def __init__(self) -> None: self._output = [] self._received = {0: [], 1: [], 2: [], 3: []} @@ -81,7 +95,7 @@ def get_received_line(self, band=0): class TestGenericPackHandler(PackHandler): - def __init__(self): + def __init__(self) -> None: PackHandler.__init__(self, Backend(), None) @classmethod @@ -573,7 +587,7 @@ def test_handle_shallow_request_unshallows(self): class TestProtocolGraphWalker: - def __init__(self): + def __init__(self) -> None: self.acks = [] self.lines = [] self.wants_satisified = False diff --git a/dulwich/tests/test_walk.py b/dulwich/tests/test_walk.py index 14312d28e..4da428e94 100644 --- a/dulwich/tests/test_walk.py +++ b/dulwich/tests/test_walk.py @@ -25,8 +25,7 @@ from dulwich.tests import TestCase -from ..diff_tree import (CHANGE_MODIFY, CHANGE_RENAME, RenameDetector, - TreeChange) +from ..diff_tree import CHANGE_MODIFY, CHANGE_RENAME, RenameDetector, TreeChange from ..errors import MissingCommitError from ..object_store import MemoryObjectStore from ..objects import Blob, Commit @@ -35,11 +34,11 @@ class TestWalkEntry: - def __init__(self, commit, changes): + def __init__(self, commit, changes) -> None: self.commit = commit self.changes = changes - def __repr__(self): + def __repr__(self) -> str: return "".format( self.commit.id, self.changes, diff --git a/dulwich/tests/test_web.py b/dulwich/tests/test_web.py index c384b2871..b7466e801 100644 --- a/dulwich/tests/test_web.py +++ b/dulwich/tests/test_web.py @@ -32,18 +32,31 @@ from ..objects import Blob from ..repo import BaseRepo, MemoryRepo from ..server import DictBackend -from ..web import (HTTP_ERROR, HTTP_FORBIDDEN, HTTP_NOT_FOUND, HTTP_OK, - GunzipFilter, HTTPGitApplication, HTTPGitRequest, - _LengthLimitedFile, get_idx_file, get_info_packs, - get_info_refs, get_loose_object, get_pack_file, - get_text_file, handle_service_request, send_file) +from ..web import ( + HTTP_ERROR, + HTTP_FORBIDDEN, + HTTP_NOT_FOUND, + HTTP_OK, + GunzipFilter, + HTTPGitApplication, + HTTPGitRequest, + _LengthLimitedFile, + get_idx_file, + get_info_packs, + get_info_refs, + get_loose_object, + get_pack_file, + get_text_file, + handle_service_request, + send_file, +) from .utils import make_object, make_tag class MinimalistWSGIInputStream: """WSGI input stream with no 'seek()' and 'tell()' methods.""" - def __init__(self, data): + def __init__(self, data) -> None: self.data = data self.pos = 0 @@ -69,7 +82,7 @@ def tell(self): class TestHTTPGitRequest(HTTPGitRequest): """HTTPGitRequest with overridden methods to help test caching.""" - def __init__(self, *args, **kwargs): + def __init__(self, *args, **kwargs) -> None: HTTPGitRequest.__init__(self, *args, **kwargs) self.cached = None @@ -142,7 +155,7 @@ def test_send_file_buffered(self): def test_send_file_error(self): class TestFile: - def __init__(self, exc_class): + def __init__(self, exc_class) -> None: self.closed = False self._exc_class = exc_class @@ -270,11 +283,11 @@ def test_get_info_refs_not_found(self): def test_get_info_packs(self): class TestPackData: - def __init__(self, sha): + def __init__(self, sha) -> None: self.filename = "pack-%s.pack" % sha class TestPack: - def __init__(self, sha): + def __init__(self, sha) -> None: self.data = TestPackData(sha) packs = [TestPack(str(i) * 40) for i in range(1, 4)] @@ -308,7 +321,7 @@ def __init__( proto, stateless_rpc=None, advertise_refs=False, - ): + ) -> None: self.args = args self.proto = proto self.stateless_rpc = stateless_rpc @@ -536,10 +549,9 @@ def test_call(self): self._test_call(self.example_text, *self._get_zstream(self.example_text)) def test_call_no_seek(self): - """ - This ensures that the gunzipping code doesn't require any methods on + """This ensures that the gunzipping code doesn't require any methods on 'wsgi.input' except for '.read()'. (In particular, it shouldn't - require '.seek()'. See https://github.com/jelmer/dulwich/issues/140.) + require '.seek()'. See https://github.com/jelmer/dulwich/issues/140.). """ zstream, zlength = self._get_zstream(self.example_text) self._test_call( @@ -549,8 +561,7 @@ def test_call_no_seek(self): ) def test_call_no_working_seek(self): - """ - Similar to 'test_call_no_seek', but this time the methods are available + """Similar to 'test_call_no_seek', but this time the methods are available (but defunct). See https://github.com/jonashaag/klaus/issues/154. """ zstream, zlength = self._get_zstream(self.example_text) diff --git a/dulwich/tests/utils.py b/dulwich/tests/utils.py index 0b19960e5..33c80969e 100644 --- a/dulwich/tests/utils.py +++ b/dulwich/tests/utils.py @@ -33,9 +33,16 @@ from ..index import commit_tree from ..objects import Commit, FixedSha, Tag, object_class -from ..pack import (DELTA_TYPES, OFS_DELTA, REF_DELTA, SHA1Writer, - create_delta, obj_sha, write_pack_header, - write_pack_object) +from ..pack import ( + DELTA_TYPES, + OFS_DELTA, + REF_DELTA, + SHA1Writer, + create_delta, + obj_sha, + write_pack_header, + write_pack_object, +) from ..repo import Repo # Plain files are very frequently used in tests, so let the mode be very short. @@ -295,6 +302,7 @@ def build_commit_graph(object_store, commit_spec, trees=None, attrs=None): attrs: A dict of commit number -> (dict of attribute -> value) for assigning additional values to the commits. Returns: The list of commit objects created. + Raises: ValueError: If an undefined commit identifier is listed as a parent. """ @@ -345,7 +353,6 @@ def build_commit_graph(object_store, commit_spec, trees=None, attrs=None): def setup_warning_catcher(): """Wrap warnings.showwarning with code that records warnings.""" - caught_warnings = [] original_showwarning = warnings.showwarning diff --git a/dulwich/walk.py b/dulwich/walk.py index e57a12aca..c97dd5637 100644 --- a/dulwich/walk.py +++ b/dulwich/walk.py @@ -26,8 +26,12 @@ from itertools import chain from typing import Deque, List, Optional, Set, Tuple -from .diff_tree import (RENAME_CHANGE_TYPES, RenameDetector, tree_changes, - tree_changes_for_merge) +from .diff_tree import ( + RENAME_CHANGE_TYPES, + RenameDetector, + tree_changes, + tree_changes_for_merge, +) from .errors import MissingCommitError from .objects import Commit, ObjectID, Tag @@ -43,7 +47,7 @@ class WalkEntry: """Object encapsulating a single result from a walk.""" - def __init__(self, walker, commit): + def __init__(self, walker, commit) -> None: self.commit = commit self._store = walker.store self._get_parents = walker.get_parents @@ -111,7 +115,7 @@ def changes(self, path_prefix=None): self._changes[path_prefix] = cached return self._changes[path_prefix] - def __repr__(self): + def __repr__(self) -> str: return "".format( self.commit.id, self.changes(), @@ -121,7 +125,7 @@ def __repr__(self): class _CommitTimeQueue: """Priority queue of WalkEntry objects by commit time.""" - def __init__(self, walker: "Walker"): + def __init__(self, walker: "Walker") -> None: self._walker = walker self._store = walker.store self._get_parents = walker.get_parents @@ -244,7 +248,7 @@ def __init__( until: Optional[int] = None, get_parents=lambda commit: commit.parents, queue_cls=_CommitTimeQueue, - ): + ) -> None: """Constructor. Args: diff --git a/dulwich/web.py b/dulwich/web.py index 2b0312c3e..444caaeea 100644 --- a/dulwich/web.py +++ b/dulwich/web.py @@ -28,15 +28,23 @@ from io import BytesIO from typing import List, Optional, Tuple from urllib.parse import parse_qs -from wsgiref.simple_server import (ServerHandler, WSGIRequestHandler, - WSGIServer, make_server) +from wsgiref.simple_server import ( + ServerHandler, + WSGIRequestHandler, + WSGIServer, + make_server, +) from dulwich import log_utils from .protocol import ReceivableProtocol from .repo import BaseRepo, NotGitRepository, Repo -from .server import (DEFAULT_HANDLERS, DictBackend, generate_info_refs, - generate_objects_info_packs) +from .server import ( + DEFAULT_HANDLERS, + DictBackend, + generate_info_refs, + generate_objects_info_packs, +) logger = log_utils.getLogger(__name__) @@ -248,7 +256,7 @@ def _chunk_iter(f): class ChunkReader: - def __init__(self, f): + def __init__(self, f) -> None: self._iter = _chunk_iter(f) self._buffer = [] @@ -272,7 +280,7 @@ class _LengthLimitedFile: but not implemented in wsgiref as of 2.5. """ - def __init__(self, input, max_bytes): + def __init__(self, input, max_bytes) -> None: self._input = input self._bytes_avail = max_bytes @@ -319,7 +327,7 @@ class HTTPGitRequest: environ: the WSGI environment for the request. """ - def __init__(self, environ, start_response, dumb: bool = False, handlers=None): + def __init__(self, environ, start_response, dumb: bool = False, handlers=None) -> None: self.environ = environ self.dumb = dumb self.handlers = handlers @@ -405,7 +413,7 @@ class HTTPGitApplication: ("POST", re.compile("/git-receive-pack$")): handle_service_request, } - def __init__(self, backend, dumb: bool = False, handlers=None, fallback_app=None): + def __init__(self, backend, dumb: bool = False, handlers=None, fallback_app=None) -> None: self.backend = backend self.dumb = dumb self.handlers = dict(DEFAULT_HANDLERS) @@ -443,7 +451,7 @@ class GunzipFilter: passing on to the underlying application. """ - def __init__(self, application): + def __init__(self, application) -> None: self.app = application def __call__(self, environ, start_response): @@ -464,7 +472,7 @@ class LimitedInputFilter: specified in Content-Length. """ - def __init__(self, application): + def __init__(self, application) -> None: self.app = application def __call__(self, environ, start_response): @@ -521,8 +529,7 @@ def log_error(self, *args): logger.error(*args) def handle(self): - """Handle a single HTTP request""" - + """Handle a single HTTP request.""" self.raw_requestline = self.rfile.readline() if not self.parse_request(): # An error code has been sent, just exit return @@ -536,7 +543,7 @@ def handle(self): class WSGIServerLogger(WSGIServer): def handle_error(self, request, client_address): - """Handle an error. """ + """Handle an error.""" logger.exception( "Exception happened during processing of request from %s" % str(client_address) diff --git a/pyproject.toml b/pyproject.toml index 3399ff2c4..9b64951e1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -66,3 +66,18 @@ license-files = ["COPYING"] [tool.setuptools.dynamic] version = {attr = "dulwich.__version__"} + +[tool.ruff] +select = [ + "ANN", + "D", + "E", + "F", + "I" +] +ignore = [ + "ANN101", # missing-type-self +] + +[tool.ruff.pydocstyle] +convention = "google" From e6ccc98835fe4610ad1647fe28b5bf239ae3f59e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jelmer=20Vernoo=C4=B3?= Date: Wed, 10 May 2023 16:09:09 +0000 Subject: [PATCH 2/2] Add more typing --- dulwich/client.py | 12 +++++++----- dulwich/config.py | 6 ++++-- dulwich/fastexport.py | 7 ++++--- dulwich/greenthreads.py | 8 +++++--- dulwich/mailmap.py | 4 +++- dulwich/object_store.py | 21 +++++++++++++-------- dulwich/objects.py | 10 ++++++---- dulwich/pack.py | 9 +++++---- dulwich/refs.py | 6 +++--- dulwich/repo.py | 7 ++++--- dulwich/server.py | 8 ++++---- dulwich/tests/test_client.py | 3 ++- dulwich/tests/test_pack.py | 3 ++- dulwich/tests/test_server.py | 9 +++++---- dulwich/walk.py | 5 +++-- dulwich/web.py | 2 +- 16 files changed, 71 insertions(+), 49 deletions(-) diff --git a/dulwich/client.py b/dulwich/client.py index 2fd77c858..e4510be61 100644 --- a/dulwich/client.py +++ b/dulwich/client.py @@ -190,7 +190,7 @@ class ReportStatusParser: def __init__(self) -> None: self._done = False self._pack_status = None - self._ref_statuses = [] + self._ref_statuses: List[bytes] = [] def check(self): """Check if there were any errors and, if so, raise exceptions. @@ -427,8 +427,8 @@ def _read_shallow_updates(pkt_seq): class _v1ReceivePackHeader: def __init__(self, capabilities, old_refs, new_refs) -> None: - self.want = [] - self.have = [] + self.want: List[bytes] = [] + self.have: List[bytes] = [] self._it = self._handle_receive_pack_head(capabilities, old_refs, new_refs) self.sent_capabilities = False @@ -646,7 +646,7 @@ def __init__( to """ self._report_activity = report_activity - self._report_status_parser = None + self._report_status_parser: Optional[ReportStatusParser] = None self._fetch_capabilities = set(UPLOAD_CAPABILITIES) self._fetch_capabilities.add(capability_agent()) self._send_capabilities = set(RECEIVE_CAPABILITIES) @@ -915,6 +915,7 @@ def progress(x): pass if CAPABILITY_REPORT_STATUS in capabilities: + assert self._report_status_parser is not None pktline_parser = PktLineParser(self._report_status_parser.handle_packet) for chan, data in _read_side_band64k_data(proto.read_pkt_seq()): if chan == SIDE_BAND_CHANNEL_DATA: @@ -927,6 +928,7 @@ def progress(x): "Invalid sideband channel %d" % chan) else: if CAPABILITY_REPORT_STATUS in capabilities: + assert self._report_status_parser for pkt in proto.read_pkt_seq(): self._report_status_parser.handle_packet(pkt) if self._report_status_parser is not None: @@ -1729,7 +1731,7 @@ def __init__( "GIT_SSH_COMMAND", os.environ.get("GIT_SSH") ) super().__init__(**kwargs) - self.alternative_paths = {} + self.alternative_paths: Dict[bytes, bytes] = {} if vendor is not None: self.ssh_vendor = vendor else: diff --git a/dulwich/config.py b/dulwich/config.py index dd04dc9c5..64f4ac6cf 100644 --- a/dulwich/config.py +++ b/dulwich/config.py @@ -40,6 +40,8 @@ Tuple, Union, overload, + Any, + Dict, ) from .file import GitFile @@ -60,8 +62,8 @@ def lower_key(key): class CaseInsensitiveOrderedMultiDict(MutableMapping): def __init__(self) -> None: - self._real = [] - self._keyed = {} + self._real: List[Any] = [] + self._keyed: Dict[Any, Any] = {} @classmethod def make(cls, dict_in=None): diff --git a/dulwich/fastexport.py b/dulwich/fastexport.py index 0c30e2f86..c5a367196 100644 --- a/dulwich/fastexport.py +++ b/dulwich/fastexport.py @@ -22,6 +22,7 @@ """Fast export/import functionality.""" import stat +from typing import Dict, Tuple from fastimport import commands, parser, processor from fastimport import errors as fastimport_errors @@ -42,7 +43,7 @@ class GitFastExporter: def __init__(self, outf, store) -> None: self.outf = outf self.store = store - self.markers = {} + self.markers: Dict[bytes, bytes] = {} self._marker_idx = 0 def print_cmd(self, cmd): @@ -125,8 +126,8 @@ def __init__(self, repo, params=None, verbose=False, outf=None) -> None: processor.ImportProcessor.__init__(self, params, verbose) self.repo = repo self.last_commit = ZERO_SHA - self.markers = {} - self._contents = {} + self.markers: Dict[bytes, bytes] = {} + self._contents: Dict[bytes, Tuple[int, bytes]] = {} def lookup_object(self, objectish): if objectish.startswith(b":"): diff --git a/dulwich/greenthreads.py b/dulwich/greenthreads.py index 6593defee..db6370345 100644 --- a/dulwich/greenthreads.py +++ b/dulwich/greenthreads.py @@ -25,12 +25,14 @@ import gevent from gevent import pool +from typing import Set, Tuple, Optional, FrozenSet + from .object_store import ( MissingObjectFinder, _collect_ancestors, _collect_filetree_revs, ) -from .objects import Commit, Tag +from .objects import Commit, Tag, ObjectID def _split_commits_and_tags(obj_store, lst, *, ignore_unknown=False, pool=None): @@ -89,7 +91,7 @@ def collect_tree_sha(sha): have_commits, have_tags = _split_commits_and_tags(object_store, haves, ignore_unknown=True, pool=p) want_commits, want_tags = _split_commits_and_tags(object_store, wants, ignore_unknown=False, pool=p) - all_ancestors = _collect_ancestors(object_store, have_commits)[0] + all_ancestors: FrozenSet[ObjectID] = frozenset(_collect_ancestors(object_store, have_commits)[0]) missing_commits, common_commits = _collect_ancestors( object_store, want_commits, all_ancestors ) @@ -101,7 +103,7 @@ def collect_tree_sha(sha): self.sha_done.add(t) missing_tags = want_tags.difference(have_tags) wants = missing_commits.union(missing_tags) - self.objects_to_send = {(w, None, False) for w in wants} + self.objects_to_send: Set[Tuple[ObjectID, Optional[bytes], Optional[int], bool]] = {(w, None, 0, False) for w in wants} if progress is None: self.progress = lambda x: None else: diff --git a/dulwich/mailmap.py b/dulwich/mailmap.py index 592c222c8..e4251d7db 100644 --- a/dulwich/mailmap.py +++ b/dulwich/mailmap.py @@ -20,6 +20,8 @@ """Mailmap file reader.""" +from typing import Dict, Tuple, Optional + def parse_identity(text): # TODO(jelmer): Integrate this with dulwich.fastexport.split_email and @@ -62,7 +64,7 @@ class Mailmap: """Class for accessing a mailmap file.""" def __init__(self, map=None) -> None: - self._table = {} + self._table: Dict[Tuple[Optional[str], str], Tuple[str, str]] = {} if map: for (canonical_identity, from_identity) in map: self.add_entry(canonical_identity, from_identity) diff --git a/dulwich/object_store.py b/dulwich/object_store.py index f60312ee8..3675800e3 100644 --- a/dulwich/object_store.py +++ b/dulwich/object_store.py @@ -31,6 +31,7 @@ from typing import ( Callable, Dict, + FrozenSet, Iterable, Iterator, List, @@ -360,7 +361,7 @@ def close(self): class PackBasedObjectStore(BaseObjectStore): def __init__(self, pack_compression_level=-1) -> None: - self._pack_cache = {} + self._pack_cache: Dict[str, Pack] = {} self.pack_compression_level = pack_compression_level def add_pack( @@ -995,7 +996,7 @@ class MemoryObjectStore(BaseObjectStore): def __init__(self) -> None: super().__init__() - self._data = {} + self._data: Dict[str, ShaFile] = {} self.pack_compression_level = -1 def _to_hexsha(self, sha): @@ -1269,7 +1270,7 @@ def __init__( # in fact, what we 'want' is commits, tags, and others # we've found missing - self.objects_to_send = { + self.objects_to_send: Set[Tuple[ObjectID, Optional[bytes], Optional[int], bool]] = { (w, None, Commit.type_num, False) for w in missing_commits} missing_tags = want_tags.difference(have_tags) @@ -1293,7 +1294,7 @@ def get_remote_has(self): def add_todo(self, entries: Iterable[Tuple[ObjectID, Optional[bytes], Optional[int], bool]]): self.objects_to_send.update([e for e in entries if e[0] not in self.sha_done]) - def __next__(self) -> Tuple[bytes, PackHint]: + def __next__(self) -> Tuple[bytes, Optional[PackHint]]: while True: if not self.objects_to_send: self.progress(("counting objects: %d, done.\n" % len(self.sha_done)).encode("ascii")) @@ -1321,7 +1322,11 @@ def __next__(self) -> Tuple[bytes, PackHint]: self.sha_done.add(sha) if len(self.sha_done) % 1000 == 0: self.progress(("counting objects: %d\r" % len(self.sha_done)).encode("ascii")) - return (sha, (type_num, name)) + if type_num is None: + pack_hint = None + else: + pack_hint = (type_num, name) + return (sha, pack_hint) def __iter__(self): return self @@ -1344,7 +1349,7 @@ def __init__(self, local_heads, get_parents, shallow=None) -> None: """ self.heads = set(local_heads) self.get_parents = get_parents - self.parents = {} + self.parents: Dict[ObjectID, Optional[List[ObjectID]]] = {} if shallow is None: shallow = set() self.shallow = shallow @@ -1610,8 +1615,8 @@ def commit(): def _collect_ancestors( store: ObjectContainer, heads, - common=frozenset(), - shallow=frozenset(), + common: FrozenSet[ObjectID] = frozenset(), + shallow: FrozenSet[ObjectID] = frozenset(), get_parents=lambda commit: commit.parents, ): """Collect all ancestors of heads up to (excluding) those in common. diff --git a/dulwich/objects.py b/dulwich/objects.py index 8fd9032b2..7f5b65321 100644 --- a/dulwich/objects.py +++ b/dulwich/objects.py @@ -1076,7 +1076,7 @@ class Tree(ShaFile): def __init__(self) -> None: super().__init__() - self._entries = {} + self._entries: Dict[bytes, Tuple[int, bytes]] = {} @classmethod def from_path(cls, filename): @@ -1381,11 +1381,11 @@ class Commit(ShaFile): def __init__(self) -> None: super().__init__() - self._parents = [] + self._parents: List[bytes] = [] self._encoding = None - self._mergetag = [] + self._mergetag: List[Tag] = [] self._gpgsig = None - self._extra = [] + self._extra: List[Tuple[bytes, bytes]] = [] self._author_timezone_neg_utc = False self._commit_timezone_neg_utc = False @@ -1412,6 +1412,7 @@ def _deserialize(self, chunks): if field == _TREE_HEADER: self._tree = value elif field == _PARENT_HEADER: + assert value is not None self._parents.append(value) elif field == _AUTHOR_HEADER: author_info = parse_time_entry(value) @@ -1420,6 +1421,7 @@ def _deserialize(self, chunks): elif field == _ENCODING_HEADER: self._encoding = value elif field == _MERGETAG_HEADER: + assert value is not None self._mergetag.append(Tag.from_string(value + b"\n")) elif field == _GPGSIG_HEADER: self._gpgsig = value diff --git a/dulwich/pack.py b/dulwich/pack.py index 9b31e7eed..b4fdf3c94 100644 --- a/dulwich/pack.py +++ b/dulwich/pack.py @@ -201,6 +201,7 @@ class UnpackedObject: obj_chunks: Optional[List[bytes]] delta_base: Union[None, bytes, int] decomp_chunks: List[bytes] + comp_chunks: Optional[List[bytes]] # TODO(dborowitz): read_zlib_chunks and unpack_object could very well be # methods of this object. @@ -1167,7 +1168,7 @@ def __init__(self, filename, file=None, size=None) -> None: else: self._file = file (version, self._num_objects) = read_pack_header(self._file.read) - self._offset_cache = LRUSizeCache( + self._offset_cache = LRUSizeCache[int, Tuple[int, OldUnpackedObject]]( 1024 * 1024 * 20, compute_size=_compute_object_size ) @@ -1239,7 +1240,7 @@ def iter_unpacked(self, *, include_comp: bool = False): # Back up over unused data. self._file.seek(-len(unused), SEEK_CUR) - def iterentries(self, progress: Optional[ProgressFn] = None, resolve_ext_ref: Optional[ResolveExtRefFn] = None): + def iterentries(self, progress=None, resolve_ext_ref: Optional[ResolveExtRefFn] = None): """Yield entries summarizing the contents of this pack. Args: @@ -1957,7 +1958,7 @@ class PackChunkGenerator: def __init__(self, num_records=None, records=None, progress=None, compression_level=-1, reuse_compressed=True) -> None: self.cs = sha1(b"") - self.entries = {} + self.entries: Dict[Union[int, bytes], Tuple[int, int]] = {} self._it = self._pack_data_chunks( num_records=num_records, records=records, progress=progress, compression_level=compression_level, reuse_compressed=reuse_compressed) @@ -2607,7 +2608,7 @@ def extend_pack(f: BinaryIO, object_ids: Set[ObjectID], get_raw, *, compression_ try: - from dulwich._pack import ( + from dulwich._pack import ( # type: ignore # noqa: F811 apply_delta, # type: ignore # noqa: F811 bisect_find_sha, # type: ignore # noqa: F811 ) diff --git a/dulwich/refs.py b/dulwich/refs.py index 815907d56..3c2f452a8 100644 --- a/dulwich/refs.py +++ b/dulwich/refs.py @@ -23,7 +23,7 @@ import os import warnings from contextlib import suppress -from typing import Dict, Optional +from typing import Dict, Optional, Set, Any from .errors import PackedRefsException, RefFormatError from .file import GitFile, ensure_dir_exists @@ -442,8 +442,8 @@ class DictRefsContainer(RefsContainer): def __init__(self, refs, logger=None) -> None: super().__init__(logger=logger) self._refs = refs - self._peeled = {} - self._watchers = set() + self._peeled: Dict[bytes, ObjectID] = {} + self._watchers: Set[Any] = set() def allkeys(self): return self._refs.keys() diff --git a/dulwich/repo.py b/dulwich/repo.py index e653b28ec..161fbaf0b 100644 --- a/dulwich/repo.py +++ b/dulwich/repo.py @@ -46,6 +46,7 @@ Set, Tuple, Union, + Any ) if TYPE_CHECKING: @@ -1797,10 +1798,10 @@ class MemoryRepo(BaseRepo): def __init__(self) -> None: from .config import ConfigFile - self._reflog = [] + self._reflog: List[Any] = [] refs_container = DictRefsContainer({}, logger=self._append_reflog) - BaseRepo.__init__(self, MemoryObjectStore(), refs_container) - self._named_files = {} + BaseRepo.__init__(self, MemoryObjectStore(), refs_container) # type: ignore + self._named_files: Dict[str, bytes] = {} self.bare = True self._config = ConfigFile() self._description = None diff --git a/dulwich/server.py b/dulwich/server.py index 01b167ce3..79d4f41c1 100644 --- a/dulwich/server.py +++ b/dulwich/server.py @@ -227,7 +227,7 @@ class PackHandler(Handler): def __init__(self, backend, proto, stateless_rpc=False) -> None: super().__init__(backend, proto, stateless_rpc) - self._client_capabilities = None + self._client_capabilities: Optional[Set[bytes]] = None # Flags needed for the no-done capability self._done_received = False @@ -763,7 +763,7 @@ class SingleAckGraphWalkerImpl: def __init__(self, walker) -> None: self.walker = walker - self._common = [] + self._common: List[bytes] = [] def ack(self, have_ref): if not self._common: @@ -808,7 +808,7 @@ class MultiAckGraphWalkerImpl: def __init__(self, walker) -> None: self.walker = walker self._found_base = False - self._common = [] + self._common: List[bytes] = [] def ack(self, have_ref): self._common.append(have_ref) @@ -866,7 +866,7 @@ class MultiAckDetailedGraphWalkerImpl: def __init__(self, walker) -> None: self.walker = walker - self._common = [] + self._common: List[bytes] = [] def ack(self, have_ref): # Should only be called iff have_ref is common diff --git a/dulwich/tests/test_client.py b/dulwich/tests/test_client.py index 7bd3617b3..ee4decc10 100644 --- a/dulwich/tests/test_client.py +++ b/dulwich/tests/test_client.py @@ -23,6 +23,7 @@ import shutil import sys import tempfile +from typing import Dict import warnings from io import BytesIO from unittest.mock import patch @@ -1090,7 +1091,7 @@ def test_url_redirect_location(self): # otherwise without an active internet connection class PoolManagerMock: def __init__(self) -> None: - self.headers = {} + self.headers: Dict[str, str] = {} def request(self, method, url, fields=None, headers=None, redirect=True, preload_content=True): base_url = url[: -len(tail)] diff --git a/dulwich/tests/test_pack.py b/dulwich/tests/test_pack.py index 90c2c5157..b63f0c47e 100644 --- a/dulwich/tests/test_pack.py +++ b/dulwich/tests/test_pack.py @@ -29,6 +29,7 @@ import zlib from hashlib import sha1 from io import BytesIO +from typing import Set from dulwich.tests import TestCase @@ -943,7 +944,7 @@ class TestPackIterator(DeltaChainIterator): def __init__(self, *args, **kwargs) -> None: super().__init__(*args, **kwargs) - self._unpacked_offsets = set() + self._unpacked_offsets: Set[int] = set() def _result(self, unpacked): """Return entries in the same format as build_pack.""" diff --git a/dulwich/tests/test_server.py b/dulwich/tests/test_server.py index f54247413..d1d51bcbc 100644 --- a/dulwich/tests/test_server.py +++ b/dulwich/tests/test_server.py @@ -25,6 +25,7 @@ import sys import tempfile from io import BytesIO +from typing import Dict, List from dulwich.tests import TestCase @@ -66,8 +67,8 @@ class TestProto: def __init__(self) -> None: - self._output = [] - self._received = {0: [], 1: [], 2: [], 3: []} + self._output: List[bytes] = [] + self._received: Dict[int, List[bytes]] = {0: [], 1: [], 2: [], 3: []} def set_output(self, output_lines): self._output = output_lines @@ -588,8 +589,8 @@ def test_handle_shallow_request_unshallows(self): class TestProtocolGraphWalker: def __init__(self) -> None: - self.acks = [] - self.lines = [] + self.acks: List[bytes] = [] + self.lines: List[bytes] = [] self.wants_satisified = False self.stateless_rpc = None self.advertise_refs = False diff --git a/dulwich/walk.py b/dulwich/walk.py index c97dd5637..c0e70c177 100644 --- a/dulwich/walk.py +++ b/dulwich/walk.py @@ -24,11 +24,12 @@ import collections import heapq from itertools import chain -from typing import Deque, List, Optional, Set, Tuple +from typing import Deque, List, Optional, Set, Tuple, Dict from .diff_tree import ( RENAME_CHANGE_TYPES, RenameDetector, + TreeChange, tree_changes, tree_changes_for_merge, ) @@ -51,7 +52,7 @@ def __init__(self, walker, commit) -> None: self.commit = commit self._store = walker.store self._get_parents = walker.get_parents - self._changes = {} + self._changes: Dict[str, List[TreeChange]] = {} self._rename_detector = walker.rename_detector def changes(self, path_prefix=None): diff --git a/dulwich/web.py b/dulwich/web.py index 444caaeea..a9c0e77d5 100644 --- a/dulwich/web.py +++ b/dulwich/web.py @@ -258,7 +258,7 @@ class ChunkReader: def __init__(self, f) -> None: self._iter = _chunk_iter(f) - self._buffer = [] + self._buffer: List[bytes] = [] def read(self, n): while sum(map(len, self._buffer)) < n: