summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--git/cmd.py53
-rw-r--r--git/config.py18
-rw-r--r--git/index/fun.py2
-rw-r--r--git/objects/base.py3
-rw-r--r--git/objects/commit.py6
-rw-r--r--git/objects/submodule/base.py13
-rw-r--r--git/objects/tree.py4
-rw-r--r--git/objects/util.py12
-rw-r--r--git/refs/head.py5
-rw-r--r--git/refs/log.py2
-rw-r--r--git/refs/reference.py6
-rw-r--r--git/refs/symbolic.py91
-rw-r--r--git/repo/base.py13
-rw-r--r--git/util.py8
-rw-r--r--pyproject.toml2
15 files changed, 138 insertions, 100 deletions
diff --git a/git/cmd.py b/git/cmd.py
index 4404981e..f8212745 100644
--- a/git/cmd.py
+++ b/git/cmd.py
@@ -39,10 +39,10 @@ from .util import (
# typing ---------------------------------------------------------------------------
-from typing import (Any, AnyStr, BinaryIO, Callable, Dict, IO, List, Mapping,
+from typing import (Any, AnyStr, BinaryIO, Callable, Dict, IO, Iterator, List, Mapping,
Sequence, TYPE_CHECKING, TextIO, Tuple, Union, cast, overload)
-from git.types import PathLike, Literal, TBD
+from git.types import PathLike, Literal
if TYPE_CHECKING:
from git.repo.base import Repo
@@ -146,11 +146,11 @@ def dashify(string: str) -> str:
return string.replace('_', '-')
-def slots_to_dict(self, exclude: Sequence[str] = ()) -> Dict[str, Any]:
+def slots_to_dict(self: object, exclude: Sequence[str] = ()) -> Dict[str, Any]:
return {s: getattr(self, s) for s in self.__slots__ if s not in exclude}
-def dict_to_slots_and__excluded_are_none(self, d: Mapping[str, Any], excluded: Sequence[str] = ()) -> None:
+def dict_to_slots_and__excluded_are_none(self: object, d: Mapping[str, Any], excluded: Sequence[str] = ()) -> None:
for k, v in d.items():
setattr(self, k, v)
for k in excluded:
@@ -192,7 +192,7 @@ class Git(LazyMixin):
def __getstate__(self) -> Dict[str, Any]:
return slots_to_dict(self, exclude=self._excluded_)
- def __setstate__(self, d) -> None:
+ def __setstate__(self, d: Dict[str, Any]) -> None:
dict_to_slots_and__excluded_are_none(self, d, excluded=self._excluded_)
# CONFIGURATION
@@ -434,10 +434,13 @@ class Git(LazyMixin):
if self.proc is not None:
status = self.proc.wait()
- def read_all_from_possibly_closed_stream(stream):
- try:
- return stderr + force_bytes(stream.read())
- except ValueError:
+ def read_all_from_possibly_closed_stream(stream: Union[IO[bytes], None]) -> bytes:
+ if stream:
+ try:
+ return stderr + force_bytes(stream.read())
+ except ValueError:
+ return stderr or b''
+ else:
return stderr or b''
if status != 0:
@@ -907,7 +910,7 @@ class Git(LazyMixin):
if self.GIT_PYTHON_TRACE == 'full':
cmdstr = " ".join(redacted_command)
- def as_text(stdout_value):
+ def as_text(stdout_value: Union[bytes, str]) -> str:
return not output_stream and safe_decode(stdout_value) or '<OUTPUT_STREAM>'
# end
@@ -932,10 +935,10 @@ class Git(LazyMixin):
else:
return stdout_value
- def environment(self):
+ def environment(self) -> Dict[str, str]:
return self._environment
- def update_environment(self, **kwargs):
+ def update_environment(self, **kwargs: Any) -> Dict[str, Union[str, None]]:
"""
Set environment variables for future git invocations. Return all changed
values in a format that can be passed back into this function to revert
@@ -962,7 +965,7 @@ class Git(LazyMixin):
return old_env
@contextmanager
- def custom_environment(self, **kwargs):
+ def custom_environment(self, **kwargs: Any) -> Iterator[None]:
"""
A context manager around the above ``update_environment`` method to restore the
environment back to its previous state after operation.
@@ -1044,6 +1047,13 @@ class Git(LazyMixin):
... # if no args given, execute called with all defaults
@overload
+ def _call_process(self, method: str,
+ istream: int,
+ as_process: Literal[True],
+ *args: Any, **kwargs: Any
+ ) -> 'Git.AutoInterrupt': ...
+
+ @overload
def _call_process(self, method: str, *args: Any, **kwargs: Any
) -> Union[str, bytes, Tuple[int, Union[str, bytes], str], 'Git.AutoInterrupt']:
...
@@ -1156,7 +1166,7 @@ class Git(LazyMixin):
return refstr.encode(defenc)
def _get_persistent_cmd(self, attr_name: str, cmd_name: str, *args: Any, **kwargs: Any
- ) -> Union['Git.AutoInterrupt', TBD]:
+ ) -> 'Git.AutoInterrupt':
cur_val = getattr(self, attr_name)
if cur_val is not None:
return cur_val
@@ -1166,12 +1176,16 @@ class Git(LazyMixin):
cmd = self._call_process(cmd_name, *args, **options)
setattr(self, attr_name, cmd)
+ cmd = cast('Git.AutoInterrupt', cmd)
return cmd
- def __get_object_header(self, cmd, ref: AnyStr) -> Tuple[str, str, int]:
- cmd.stdin.write(self._prepare_ref(ref))
- cmd.stdin.flush()
- return self._parse_object_header(cmd.stdout.readline())
+ def __get_object_header(self, cmd: 'Git.AutoInterrupt', ref: AnyStr) -> Tuple[str, str, int]:
+ if cmd.stdin and cmd.stdout:
+ cmd.stdin.write(self._prepare_ref(ref))
+ cmd.stdin.flush()
+ return self._parse_object_header(cmd.stdout.readline())
+ else:
+ raise ValueError("cmd stdin was empty")
def get_object_header(self, ref: str) -> Tuple[str, str, int]:
""" Use this method to quickly examine the type and size of the object behind
@@ -1200,7 +1214,8 @@ class Git(LazyMixin):
:note: This method is not threadsafe, you need one independent Command instance per thread to be safe !"""
cmd = self._get_persistent_cmd("cat_file_all", "cat_file", batch=True)
hexsha, typename, size = self.__get_object_header(cmd, ref)
- return (hexsha, typename, size, self.CatFileContentStream(size, cmd.stdout))
+ cmd_stdout = cmd.stdout if cmd.stdout is not None else io.BytesIO()
+ return (hexsha, typename, size, self.CatFileContentStream(size, cmd_stdout))
def clear_cache(self) -> 'Git':
"""Clear all kinds of internal caches to release resources.
diff --git a/git/config.py b/git/config.py
index ad02b437..011d0e0b 100644
--- a/git/config.py
+++ b/git/config.py
@@ -40,6 +40,7 @@ if TYPE_CHECKING:
from io import BytesIO
T_ConfigParser = TypeVar('T_ConfigParser', bound='GitConfigParser')
+T_OMD_value = TypeVar('T_OMD_value', str, bytes, int, float, bool)
if sys.version_info[:3] < (3, 7, 2):
# typing.Ordereddict not added until py 3.7.2
@@ -47,7 +48,7 @@ if sys.version_info[:3] < (3, 7, 2):
OrderedDict_OMD = OrderedDict # type: ignore # until 3.6 dropped
else:
from typing import OrderedDict # type: ignore # until 3.6 dropped
- OrderedDict_OMD = OrderedDict[str, List[_T]] # type: ignore[assignment, misc]
+ OrderedDict_OMD = OrderedDict[str, List[T_OMD_value]] # type: ignore[assignment, misc]
# -------------------------------------------------------------
@@ -97,23 +98,23 @@ class MetaParserBuilder(abc.ABCMeta):
return new_type
-def needs_values(func: Callable) -> Callable:
+def needs_values(func: Callable[..., _T]) -> Callable[..., _T]:
"""Returns method assuring we read values (on demand) before we try to access them"""
@wraps(func)
- def assure_data_present(self, *args: Any, **kwargs: Any) -> Any:
+ def assure_data_present(self: 'GitConfigParser', *args: Any, **kwargs: Any) -> _T:
self.read()
return func(self, *args, **kwargs)
# END wrapper method
return assure_data_present
-def set_dirty_and_flush_changes(non_const_func: Callable) -> Callable:
+def set_dirty_and_flush_changes(non_const_func: Callable[..., _T]) -> Callable[..., _T]:
"""Return method that checks whether given non constant function may be called.
If so, the instance will be set dirty.
Additionally, we flush the changes right to disk"""
- def flush_changes(self, *args: Any, **kwargs: Any) -> Any:
+ def flush_changes(self: 'GitConfigParser', *args: Any, **kwargs: Any) -> _T:
rval = non_const_func(self, *args, **kwargs)
self._dirty = True
self.write()
@@ -356,7 +357,7 @@ class GitConfigParser(cp.RawConfigParser, metaclass=MetaParserBuilder):
self._acquire_lock()
return self
- def __exit__(self, exception_type, exception_value, traceback) -> None:
+ def __exit__(self, *args: Any) -> None:
self.release()
def release(self) -> None:
@@ -613,12 +614,15 @@ class GitConfigParser(cp.RawConfigParser, metaclass=MetaParserBuilder):
def _write(self, fp: IO) -> None:
"""Write an .ini-format representation of the configuration state in
git compatible format"""
- def write_section(name, section_dict):
+ def write_section(name: str, section_dict: _OMD) -> None:
fp.write(("[%s]\n" % name).encode(defenc))
+
+ values: Sequence[Union[str, bytes, int, float, bool]]
for (key, values) in section_dict.items_all():
if key == "__name__":
continue
+ v: Union[str, bytes, int, float, bool]
for v in values:
fp.write(("\t%s = %s\n" % (key, self._value_to_string(v).replace('\n', '\n\t'))).encode(defenc))
# END if key is not __name__
diff --git a/git/index/fun.py b/git/index/fun.py
index 49e3f2c5..16ec744e 100644
--- a/git/index/fun.py
+++ b/git/index/fun.py
@@ -251,7 +251,7 @@ def read_cache(stream: IO[bytes]) -> Tuple[int, Dict[Tuple[PathLike, int], 'Inde
return (version, entries, extension_data, content_sha)
-def write_tree_from_cache(entries: List[IndexEntry], odb, sl: slice, si: int = 0
+def write_tree_from_cache(entries: List[IndexEntry], odb: 'GitCmdObjectDB', sl: slice, si: int = 0
) -> Tuple[bytes, List['TreeCacheTup']]:
"""Create a tree from the given sorted list of entries and put the respective
trees into the given object database
diff --git a/git/objects/base.py b/git/objects/base.py
index 64f105ca..a3b0f230 100644
--- a/git/objects/base.py
+++ b/git/objects/base.py
@@ -25,6 +25,7 @@ if TYPE_CHECKING:
from .tree import Tree
from .blob import Blob
from .submodule.base import Submodule
+ from git.refs.reference import Reference
IndexObjUnion = Union['Tree', 'Blob', 'Submodule']
@@ -59,7 +60,7 @@ class Object(LazyMixin):
assert len(binsha) == 20, "Require 20 byte binary sha, got %r, len = %i" % (binsha, len(binsha))
@classmethod
- def new(cls, repo: 'Repo', id): # @ReservedAssignment
+ def new(cls, repo: 'Repo', id: Union[str, 'Reference']) -> Commit_ish:
"""
:return: New Object instance of a type appropriate to the object type behind
id. The id of the newly created object will be a binsha even though
diff --git a/git/objects/commit.py b/git/objects/commit.py
index 9d709656..b689167f 100644
--- a/git/objects/commit.py
+++ b/git/objects/commit.py
@@ -282,7 +282,7 @@ class Commit(base.Object, TraversableIterableObj, Diffable, Serializable):
proc = repo.git.rev_list(rev, args_list, as_process=True, **kwargs)
return cls._iter_from_process_or_stream(repo, proc)
- def iter_parents(self, paths: Union[PathLike, Sequence[PathLike]] = '', **kwargs) -> Iterator['Commit']:
+ def iter_parents(self, paths: Union[PathLike, Sequence[PathLike]] = '', **kwargs: Any) -> Iterator['Commit']:
"""Iterate _all_ parents of this commit.
:param paths:
@@ -362,7 +362,7 @@ class Commit(base.Object, TraversableIterableObj, Diffable, Serializable):
def create_from_tree(cls, repo: 'Repo', tree: Union[Tree, str], message: str,
parent_commits: Union[None, List['Commit']] = None, head: bool = False,
author: Union[None, Actor] = None, committer: Union[None, Actor] = None,
- author_date: Union[None, str] = None, commit_date: Union[None, str] = None):
+ author_date: Union[None, str] = None, commit_date: Union[None, str] = None) -> 'Commit':
"""Commit the given tree, creating a commit object.
:param repo: Repo object the commit should be part of
@@ -403,7 +403,7 @@ class Commit(base.Object, TraversableIterableObj, Diffable, Serializable):
else:
for p in parent_commits:
if not isinstance(p, cls):
- raise ValueError("Parent commit '%r' must be of type %s" % (p, cls))
+ raise ValueError(f"Parent commit '{p!r}' must be of type {cls}")
# end check parent commit types
# END if parent commits are unset
diff --git a/git/objects/submodule/base.py b/git/objects/submodule/base.py
index 14351190..559d2585 100644
--- a/git/objects/submodule/base.py
+++ b/git/objects/submodule/base.py
@@ -57,6 +57,7 @@ from git.types import Commit_ish, Literal, PathLike, TBD
if TYPE_CHECKING:
from git.index import IndexFile
from git.repo import Repo
+ from git.refs import Head
# -----------------------------------------------------------------------------
@@ -265,7 +266,7 @@ class Submodule(IndexObject, TraversableIterableObj):
# end
@classmethod
- def _clone_repo(cls, repo, url, path, name, **kwargs):
+ def _clone_repo(cls, repo: 'Repo', url: str, path: PathLike, name: str, **kwargs: Any) -> 'Repo':
""":return: Repo instance of newly cloned repository
:param repo: our parent repository
:param url: url to clone from
@@ -279,7 +280,7 @@ class Submodule(IndexObject, TraversableIterableObj):
module_abspath_dir = osp.dirname(module_abspath)
if not osp.isdir(module_abspath_dir):
os.makedirs(module_abspath_dir)
- module_checkout_path = osp.join(repo.working_tree_dir, path)
+ module_checkout_path = osp.join(str(repo.working_tree_dir), path)
# end
clone = git.Repo.clone_from(url, module_checkout_path, **kwargs)
@@ -484,7 +485,7 @@ class Submodule(IndexObject, TraversableIterableObj):
def update(self, recursive: bool = False, init: bool = True, to_latest_revision: bool = False,
progress: Union['UpdateProgress', None] = None, dry_run: bool = False,
force: bool = False, keep_going: bool = False, env: Union[Mapping[str, str], None] = None,
- clone_multi_options: Union[Sequence[TBD], None] = None):
+ clone_multi_options: Union[Sequence[TBD], None] = None) -> 'Submodule':
"""Update the repository of this submodule to point to the checkout
we point at with the binsha of this instance.
@@ -712,7 +713,7 @@ class Submodule(IndexObject, TraversableIterableObj):
return self
@unbare_repo
- def move(self, module_path, configuration=True, module=True):
+ def move(self, module_path: PathLike, configuration: bool = True, module: bool = True) -> 'Submodule':
"""Move the submodule to a another module path. This involves physically moving
the repository at our current path, changing the configuration, as well as
adjusting our index entry accordingly.
@@ -742,7 +743,7 @@ class Submodule(IndexObject, TraversableIterableObj):
return self
# END handle no change
- module_checkout_abspath = join_path_native(self.repo.working_tree_dir, module_checkout_path)
+ module_checkout_abspath = join_path_native(str(self.repo.working_tree_dir), module_checkout_path)
if osp.isfile(module_checkout_abspath):
raise ValueError("Cannot move repository onto a file: %s" % module_checkout_abspath)
# END handle target files
@@ -1160,7 +1161,7 @@ class Submodule(IndexObject, TraversableIterableObj):
# END handle object state consistency
@property
- def branch(self):
+ def branch(self) -> 'Head':
""":return: The branch instance that we are to checkout
:raise InvalidGitRepositoryError: if our module is not yet checked out"""
return mkhead(self.module(), self._branch_path)
diff --git a/git/objects/tree.py b/git/objects/tree.py
index 70f36af5..0cceb59a 100644
--- a/git/objects/tree.py
+++ b/git/objects/tree.py
@@ -375,8 +375,8 @@ class Tree(IndexObject, git_diff.Diffable, util.Traversable, util.Serializable):
# END for each item
return False
- def __reversed__(self):
- return reversed(self._iter_convert_to_object(self._cache))
+ def __reversed__(self) -> Iterator[IndexObjUnion]:
+ return reversed(self._iter_convert_to_object(self._cache)) # type: ignore
def _serialize(self, stream: 'BytesIO') -> 'Tree':
"""Serialize this tree into the stream. Please note that we will assume
diff --git a/git/objects/util.py b/git/objects/util.py
index db7807c2..f627211e 100644
--- a/git/objects/util.py
+++ b/git/objects/util.py
@@ -144,20 +144,20 @@ class tzoffset(tzinfo):
def __reduce__(self) -> Tuple[Type['tzoffset'], Tuple[float, str]]:
return tzoffset, (-self._offset.total_seconds(), self._name)
- def utcoffset(self, dt) -> timedelta:
+ def utcoffset(self, dt: Union[datetime, None]) -> timedelta:
return self._offset
- def tzname(self, dt) -> str:
+ def tzname(self, dt: Union[datetime, None]) -> str:
return self._name
- def dst(self, dt) -> timedelta:
+ def dst(self, dt: Union[datetime, None]) -> timedelta:
return ZERO
utc = tzoffset(0, 'UTC')
-def from_timestamp(timestamp, tz_offset: float) -> datetime:
+def from_timestamp(timestamp: float, tz_offset: float) -> datetime:
"""Converts a timestamp + tz_offset into an aware datetime instance."""
utc_dt = datetime.fromtimestamp(timestamp, utc)
try:
@@ -305,7 +305,7 @@ class Traversable(Protocol):
@classmethod
@abstractmethod
- def _get_intermediate_items(cls, item) -> Sequence['Traversable']:
+ def _get_intermediate_items(cls, item: Any) -> Sequence['Traversable']:
"""
Returns:
Tuple of items connected to the given item.
@@ -327,7 +327,7 @@ class Traversable(Protocol):
stacklevel=2)
return self._list_traverse(*args, **kwargs)
- def _list_traverse(self, as_edge=False, *args: Any, **kwargs: Any
+ def _list_traverse(self, as_edge: bool = False, *args: Any, **kwargs: Any
) -> IterableList[Union['Commit', 'Submodule', 'Tree', 'Blob']]:
"""
:return: IterableList with the results of the traversal as produced by
diff --git a/git/refs/head.py b/git/refs/head.py
index 260bf5e7..56a87182 100644
--- a/git/refs/head.py
+++ b/git/refs/head.py
@@ -21,7 +21,7 @@ if TYPE_CHECKING:
__all__ = ["HEAD", "Head"]
-def strip_quotes(string):
+def strip_quotes(string: str) -> str:
if string.startswith('"') and string.endswith('"'):
return string[1:-1]
return string
@@ -129,14 +129,13 @@ class Head(Reference):
k_config_remote_ref = "merge" # branch to merge from remote
@classmethod
- def delete(cls, repo: 'Repo', *heads: 'Head', **kwargs: Any):
+ def delete(cls, repo: 'Repo', *heads: 'Head', force: bool = False, **kwargs: Any) -> None:
"""Delete the given heads
:param force:
If True, the heads will be deleted even if they are not yet merged into
the main development stream.
Default False"""
- force = kwargs.get("force", False)
flag = "-d"
if force:
flag = "-D"
diff --git a/git/refs/log.py b/git/refs/log.py
index 643b4114..ddd78bc7 100644
--- a/git/refs/log.py
+++ b/git/refs/log.py
@@ -157,7 +157,7 @@ class RefLog(List[RefLogEntry], Serializable):
self._read_from_file()
# END handle filepath
- def _read_from_file(self):
+ def _read_from_file(self) -> None:
try:
fmap = file_contents_ro_filepath(
self._path, stream=True, allow_mmap=True)
diff --git a/git/refs/reference.py b/git/refs/reference.py
index bc2c6e80..a3647fb3 100644
--- a/git/refs/reference.py
+++ b/git/refs/reference.py
@@ -7,7 +7,7 @@ from .symbolic import SymbolicReference, T_References
# typing ------------------------------------------------------------------
-from typing import Any, Callable, Iterator, List, Match, Optional, Tuple, Type, TypeVar, Union, TYPE_CHECKING # NOQA
+from typing import Any, Callable, Iterator, Type, Union, TYPE_CHECKING # NOQA
from git.types import Commit_ish, PathLike, TBD, Literal, _T # NOQA
if TYPE_CHECKING:
@@ -63,8 +63,8 @@ class Reference(SymbolicReference, LazyMixin, IterableObj):
#{ Interface
# @ReservedAssignment
- def set_object(self, object: Union[Commit_ish, 'SymbolicReference'], logmsg: Union[str, None] = None
- ) -> 'SymbolicReference':
+ def set_object(self, object: Union[Commit_ish, 'SymbolicReference', str], logmsg: Union[str, None] = None
+ ) -> 'Reference':
"""Special version which checks if the head-log needs an update as well
:return: self"""
oldbinsha = None
diff --git a/git/refs/symbolic.py b/git/refs/symbolic.py
index bffcfea5..b4a933aa 100644
--- a/git/refs/symbolic.py
+++ b/git/refs/symbolic.py
@@ -26,7 +26,11 @@ from git.types import Commit_ish, PathLike, TBD, Literal
if TYPE_CHECKING:
from git.repo import Repo
- from git.refs import Head, TagReference, Reference
+ from git.refs import Head, TagReference, RemoteReference, Reference
+ from .log import RefLogEntry
+ from git.config import GitConfigParser
+ from git.objects.commit import Actor
+
T_References = TypeVar('T_References', bound='SymbolicReference')
@@ -36,7 +40,7 @@ T_References = TypeVar('T_References', bound='SymbolicReference')
__all__ = ["SymbolicReference"]
-def _git_dir(repo: 'Repo', path: PathLike) -> PathLike:
+def _git_dir(repo: 'Repo', path: Union[PathLike, None]) -> PathLike:
""" Find the git dir that's appropriate for the path"""
name = f"{path}"
if name in ['HEAD', 'ORIG_HEAD', 'FETCH_HEAD', 'index', 'logs']:
@@ -136,11 +140,12 @@ class SymbolicReference(object):
# alright.
@classmethod
- def dereference_recursive(cls, repo: 'Repo', ref_path: PathLike) -> str:
+ def dereference_recursive(cls, repo: 'Repo', ref_path: Union[PathLike, None]) -> str:
"""
:return: hexsha stored in the reference at the given ref_path, recursively dereferencing all
intermediate references as required
:param repo: the repository containing the reference at ref_path"""
+
while True:
hexsha, ref_path = cls._get_ref_info(repo, ref_path)
if hexsha is not None:
@@ -148,14 +153,15 @@ class SymbolicReference(object):
# END recursive dereferencing
@classmethod
- def _get_ref_info_helper(cls, repo: 'Repo', ref_path: PathLike):
+ def _get_ref_info_helper(cls, repo: 'Repo', ref_path: Union[PathLike, None]
+ ) -> Union[Tuple[str, None], Tuple[None, str]]:
"""Return: (str(sha), str(target_ref_path)) if available, the sha the file at
rela_path points to, or None. target_ref_path is the reference we
point to, or None"""
tokens: Union[None, List[str], Tuple[str, str]] = None
repodir = _git_dir(repo, ref_path)
try:
- with open(os.path.join(repodir, ref_path), 'rt', encoding='UTF-8') as fp:
+ with open(os.path.join(repodir, str(ref_path)), 'rt', encoding='UTF-8') as fp:
value = fp.read().rstrip()
# Don't only split on spaces, but on whitespace, which allows to parse lines like
# 60b64ef992065e2600bfef6187a97f92398a9144 branch 'master' of git-server:/path/to/repo
@@ -187,13 +193,13 @@ class SymbolicReference(object):
raise ValueError("Failed to parse reference information from %r" % ref_path)
@classmethod
- def _get_ref_info(cls, repo, ref_path):
+ def _get_ref_info(cls, repo: 'Repo', ref_path: Union[PathLike, None]) -> Union[Tuple[str, None], Tuple[None, str]]:
"""Return: (str(sha), str(target_ref_path)) if available, the sha the file at
rela_path points to, or None. target_ref_path is the reference we
point to, or None"""
return cls._get_ref_info_helper(repo, ref_path)
- def _get_object(self):
+ def _get_object(self) -> Commit_ish:
"""
:return:
The object our ref currently refers to. Refs can be cached, they will
@@ -202,7 +208,7 @@ class SymbolicReference(object):
# Our path will be resolved to the hexsha which will be used accordingly
return Object.new_from_sha(self.repo, hex_to_bin(self.dereference_recursive(self.repo, self.path)))
- def _get_commit(self):
+ def _get_commit(self) -> 'Commit':
"""
:return:
Commit object we point to, works for detached and non-detached
@@ -217,7 +223,8 @@ class SymbolicReference(object):
# END handle type
return obj
- def set_commit(self, commit: Union[Commit, 'SymbolicReference', str], logmsg=None):
+ def set_commit(self, commit: Union[Commit, 'SymbolicReference', str], logmsg: Union[str, None] = None
+ ) -> 'SymbolicReference':
"""As set_object, but restricts the type of object to be a Commit
:raise ValueError: If commit is not a Commit object or doesn't point to
@@ -246,7 +253,8 @@ class SymbolicReference(object):
return self
- def set_object(self, object, logmsg=None): # @ReservedAssignment
+ def set_object(self, object: Union[Commit_ish, 'SymbolicReference', str], logmsg: Union[str, None] = None
+ ) -> 'SymbolicReference':
"""Set the object we point to, possibly dereference our symbolic reference first.
If the reference does not exist, it will be created
@@ -273,10 +281,10 @@ class SymbolicReference(object):
# set the commit on our reference
return self._get_reference().set_object(object, logmsg)
- commit = property(_get_commit, set_commit, doc="Query or set commits directly")
- object = property(_get_object, set_object, doc="Return the object our ref currently refers to")
+ commit = property(_get_commit, set_commit, doc="Query or set commits directly") # type: ignore
+ object = property(_get_object, set_object, doc="Return the object our ref currently refers to") # type: ignore
- def _get_reference(self):
+ def _get_reference(self) -> 'Reference':
""":return: Reference Object we point to
:raise TypeError: If this symbolic reference is detached, hence it doesn't point
to a reference, but to a commit"""
@@ -285,7 +293,8 @@ class SymbolicReference(object):
raise TypeError("%s is a detached symbolic reference as it points to %r" % (self, sha))
return self.from_path(self.repo, target_ref_path)
- def set_reference(self, ref, logmsg=None):
+ def set_reference(self, ref: Union[Commit_ish, 'SymbolicReference', str],
+ logmsg: Union[str, None] = None) -> 'SymbolicReference':
"""Set ourselves to the given ref. It will stay a symbol if the ref is a Reference.
Otherwise an Object, given as Object instance or refspec, is assumed and if valid,
will be set which effectively detaches the refererence if it was a purely
@@ -326,7 +335,7 @@ class SymbolicReference(object):
raise TypeError("Require commit, got %r" % obj)
# END verify type
- oldbinsha = None
+ oldbinsha: bytes = b''
if logmsg is not None:
try:
oldbinsha = self.commit.binsha
@@ -355,10 +364,10 @@ class SymbolicReference(object):
return self
# aliased reference
- reference = property(_get_reference, set_reference, doc="Returns the Reference we point to")
- ref: Union[Commit_ish] = reference # type: ignore # Union[str, Commit_ish, SymbolicReference]
+ reference = property(_get_reference, set_reference, doc="Returns the Reference we point to") # type: ignore
+ ref: Union['Head', 'TagReference', 'RemoteReference', 'Reference'] = reference # type: ignore
- def is_valid(self):
+ def is_valid(self) -> bool:
"""
:return:
True if the reference is valid, hence it can be read and points to
@@ -371,7 +380,7 @@ class SymbolicReference(object):
return True
@property
- def is_detached(self):
+ def is_detached(self) -> bool:
"""
:return:
True if we are a detached reference, hence we point to a specific commit
@@ -382,7 +391,7 @@ class SymbolicReference(object):
except TypeError:
return True
- def log(self):
+ def log(self) -> 'RefLog':
"""
:return: RefLog for this reference. Its last entry reflects the latest change
applied to this reference
@@ -391,7 +400,8 @@ class SymbolicReference(object):
instead of calling this method repeatedly. It should be considered read-only."""
return RefLog.from_file(RefLog.path(self))
- def log_append(self, oldbinsha, message, newbinsha=None):
+ def log_append(self, oldbinsha: bytes, message: Union[str, None],
+ newbinsha: Union[bytes, None] = None) -> 'RefLogEntry':
"""Append a logentry to the logfile of this ref
:param oldbinsha: binary sha this ref used to point to
@@ -403,15 +413,19 @@ class SymbolicReference(object):
# correct to allow overriding the committer on a per-commit level.
# See https://github.com/gitpython-developers/GitPython/pull/146
try:
- committer_or_reader = self.commit.committer
+ committer_or_reader: Union['Actor', 'GitConfigParser'] = self.commit.committer
except ValueError:
committer_or_reader = self.repo.config_reader()
# end handle newly cloned repositories
- return RefLog.append_entry(committer_or_reader, RefLog.path(self), oldbinsha,
- (newbinsha is None and self.commit.binsha) or newbinsha,
- message)
+ if newbinsha is None:
+ newbinsha = self.commit.binsha
+
+ if message is None:
+ message = ''
+
+ return RefLog.append_entry(committer_or_reader, RefLog.path(self), oldbinsha, newbinsha, message)
- def log_entry(self, index):
+ def log_entry(self, index: int) -> 'RefLogEntry':
""":return: RefLogEntry at the given index
:param index: python list compatible positive or negative index
@@ -421,7 +435,7 @@ class SymbolicReference(object):
return RefLog.entry_at(RefLog.path(self), index)
@classmethod
- def to_full_path(cls, path) -> PathLike:
+ def to_full_path(cls, path: Union[PathLike, 'SymbolicReference']) -> PathLike:
"""
:return: string with a full repository-relative path which can be used to initialize
a Reference instance, for instance by using ``Reference.from_path``"""
@@ -430,12 +444,12 @@ class SymbolicReference(object):
full_ref_path = path
if not cls._common_path_default:
return full_ref_path
- if not path.startswith(cls._common_path_default + "/"):
+ if not str(path).startswith(cls._common_path_default + "/"):
full_ref_path = '%s/%s' % (cls._common_path_default, path)
return full_ref_path
@classmethod
- def delete(cls, repo, path):
+ def delete(cls, repo: 'Repo', path: PathLike) -> None:
"""Delete the reference at the given path
:param repo:
@@ -457,8 +471,8 @@ class SymbolicReference(object):
new_lines = []
made_change = False
dropped_last_line = False
- for line in reader:
- line = line.decode(defenc)
+ for line_bytes in reader:
+ line = line_bytes.decode(defenc)
_, _, line_ref = line.partition(' ')
line_ref = line_ref.strip()
# keep line if it is a comment or if the ref to delete is not
@@ -493,7 +507,9 @@ class SymbolicReference(object):
# END remove reflog
@classmethod
- def _create(cls, repo, path, resolve, reference, force, logmsg=None):
+ def _create(cls: Type[T_References], repo: 'Repo', path: PathLike, resolve: bool,
+ reference: Union['SymbolicReference', str], force: bool,
+ logmsg: Union[str, None] = None) -> T_References:
"""internal method used to create a new symbolic reference.
If resolve is False, the reference will be taken as is, creating
a proper symbolic reference. Otherwise it will be resolved to the
@@ -511,7 +527,7 @@ class SymbolicReference(object):
if not force and os.path.isfile(abs_ref_path):
target_data = str(target)
if isinstance(target, SymbolicReference):
- target_data = target.path
+ target_data = str(target.path)
if not resolve:
target_data = "ref: " + target_data
with open(abs_ref_path, 'rb') as fd:
@@ -526,8 +542,9 @@ class SymbolicReference(object):
return ref
@classmethod
- def create(cls, repo: 'Repo', path: PathLike, reference: Union[Commit_ish, str] = 'HEAD',
- logmsg: Union[str, None] = None, force: bool = False, **kwargs: Any):
+ def create(cls: Type[T_References], repo: 'Repo', path: PathLike,
+ reference: Union['SymbolicReference', str] = 'HEAD',
+ logmsg: Union[str, None] = None, force: bool = False, **kwargs: Any) -> T_References:
"""Create a new symbolic reference, hence a reference pointing , to another reference.
:param repo:
@@ -689,6 +706,6 @@ class SymbolicReference(object):
# END for each type to try
raise ValueError("Could not find reference type suitable to handle path %r" % path)
- def is_remote(self):
+ def is_remote(self) -> bool:
""":return: True if this symbolic reference points to a remote branch"""
- return self.path.startswith(self._remote_common_path_default + "/")
+ return str(self.path).startswith(self._remote_common_path_default + "/")
diff --git a/git/repo/base.py b/git/repo/base.py
index 355f9399..5581233b 100644
--- a/git/repo/base.py
+++ b/git/repo/base.py
@@ -412,13 +412,14 @@ class Repo(object):
return TagReference(self, full_path)
@staticmethod
- def _to_full_tag_path(path):
- if path.startswith(TagReference._common_path_default + '/'):
- return path
- if path.startswith(TagReference._common_default + '/'):
- return Reference._common_path_default + '/' + path
+ def _to_full_tag_path(path: PathLike) -> str:
+ path_str = str(path)
+ if path_str.startswith(TagReference._common_path_default + '/'):
+ return path_str
+ if path_str.startswith(TagReference._common_default + '/'):
+ return Reference._common_path_default + '/' + path_str
else:
- return TagReference._common_path_default + '/' + path
+ return TagReference._common_path_default + '/' + path_str
def create_head(self, path: PathLike, commit: str = 'HEAD',
force: bool = False, logmsg: Optional[str] = None
diff --git a/git/util.py b/git/util.py
index c0c0ecb7..92d95379 100644
--- a/git/util.py
+++ b/git/util.py
@@ -408,7 +408,7 @@ def expand_path(p: Union[None, PathLike], expand_vars: bool = True) -> Optional[
return None
-def remove_password_if_present(cmdline):
+def remove_password_if_present(cmdline: Sequence[str]) -> List[str]:
"""
Parse any command line argument and if on of the element is an URL with a
password, replace it by stars (in-place).
@@ -1033,7 +1033,7 @@ class IterableList(List[T_IterableObj]):
class IterableClassWatcher(type):
""" Metaclass that watches """
- def __init__(cls, name, bases, clsdict):
+ def __init__(cls, name: str, bases: List, clsdict: Dict) -> None:
for base in bases:
if type(base) == IterableClassWatcher:
warnings.warn(f"GitPython Iterable subclassed by {name}. "
@@ -1052,7 +1052,7 @@ class Iterable(metaclass=IterableClassWatcher):
_id_attribute_ = "attribute that most suitably identifies your instance"
@classmethod
- def list_items(cls, repo, *args, **kwargs):
+ def list_items(cls, repo: 'Repo', *args: Any, **kwargs: Any) -> Any:
"""
Deprecated, use IterableObj instead.
Find all items of this type - subclasses can specify args and kwargs differently.
@@ -1062,7 +1062,7 @@ class Iterable(metaclass=IterableClassWatcher):
:note: Favor the iter_items method as it will
:return:list(Item,...) list of item instances"""
- out_list = IterableList(cls._id_attribute_)
+ out_list: Any = IterableList(cls._id_attribute_)
out_list.extend(cls.iter_items(repo, *args, **kwargs))
return out_list
diff --git a/pyproject.toml b/pyproject.toml
index 6437a719..4751ffcb 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -19,7 +19,7 @@ filterwarnings = 'ignore::DeprecationWarning'
# filterwarnings ignore::WarningType # ignores those warnings
[tool.mypy]
-# disallow_untyped_defs = true
+disallow_untyped_defs = true
no_implicit_optional = true
warn_redundant_casts = true
# warn_unused_ignores = True