From f066c7adb5f5773dc1d0dd986c786bc0c5094e31 Mon Sep 17 00:00:00 2001 From: Yobmod Date: Sat, 31 Jul 2021 16:52:42 +0100 Subject: [PATCH 01/23] Add type to symbolicreference.is_remote() --- git/refs/symbolic.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/git/refs/symbolic.py b/git/refs/symbolic.py index bffcfea5f..b072f142c 100644 --- a/git/refs/symbolic.py +++ b/git/refs/symbolic.py @@ -526,8 +526,9 @@ def _create(cls, repo, path, resolve, reference, force, logmsg=None): 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 +690,6 @@ def from_path(cls, repo: 'Repo', path: PathLike) -> Union['Head', 'TagReference' # 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 + "/") From a8ee94b1998589085ae2b8a6de310d0a5dfd0ffd Mon Sep 17 00:00:00 2001 From: Yobmod Date: Sat, 31 Jul 2021 16:57:56 +0100 Subject: [PATCH 02/23] Add type to symbolicreference._create() --- git/refs/symbolic.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/git/refs/symbolic.py b/git/refs/symbolic.py index b072f142c..1000204fb 100644 --- a/git/refs/symbolic.py +++ b/git/refs/symbolic.py @@ -493,7 +493,9 @@ def delete(cls, repo, path): # 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 +513,7 @@ def _create(cls, repo, path, resolve, reference, force, logmsg=None): 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: From afd2ec5251479f48044408c7fcb7dab0494cd4c1 Mon Sep 17 00:00:00 2001 From: Yobmod Date: Sat, 31 Jul 2021 17:02:53 +0100 Subject: [PATCH 03/23] Add type to symbolicreference.delete() --- git/refs/symbolic.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/git/refs/symbolic.py b/git/refs/symbolic.py index 1000204fb..89999eda6 100644 --- a/git/refs/symbolic.py +++ b/git/refs/symbolic.py @@ -421,7 +421,7 @@ def log_entry(self, index): 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 +430,12 @@ def to_full_path(cls, path) -> PathLike: 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 +457,8 @@ def delete(cls, repo, path): 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 From 581d40d957fd3d7ee85c28c4dde4d6f28e104433 Mon Sep 17 00:00:00 2001 From: Yobmod Date: Sat, 31 Jul 2021 17:06:22 +0100 Subject: [PATCH 04/23] Add type to symbolicreference.log_append() --- git/refs/symbolic.py | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/git/refs/symbolic.py b/git/refs/symbolic.py index 89999eda6..5d3a6a0da 100644 --- a/git/refs/symbolic.py +++ b/git/refs/symbolic.py @@ -27,6 +27,10 @@ if TYPE_CHECKING: from git.repo import Repo from git.refs import Head, TagReference, Reference + from .log import RefLogEntry + from git.config import GitConfigParser + from git.objects.commit import Actor + T_References = TypeVar('T_References', bound='SymbolicReference') @@ -391,7 +395,8 @@ def log(self): 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 +408,19 @@ def log_append(self, oldbinsha, message, newbinsha=None): # 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 From 7f401fc659a7f9c84a9c88675aba498357a2916d Mon Sep 17 00:00:00 2001 From: Yobmod Date: Sat, 31 Jul 2021 17:09:54 +0100 Subject: [PATCH 05/23] Add type to symbolicreference.is_valid() --- git/refs/symbolic.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/git/refs/symbolic.py b/git/refs/symbolic.py index 5d3a6a0da..65bad6e48 100644 --- a/git/refs/symbolic.py +++ b/git/refs/symbolic.py @@ -360,9 +360,9 @@ def set_reference(self, ref, logmsg=None): # 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] + ref: Union['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 @@ -375,7 +375,7 @@ def is_valid(self): 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 @@ -386,7 +386,7 @@ def is_detached(self): 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 From e8442eead72bfc2a547234d0289d0f90642167fd Mon Sep 17 00:00:00 2001 From: Yobmod Date: Sat, 31 Jul 2021 17:15:33 +0100 Subject: [PATCH 06/23] Add type to symbolicreference.set_reference() --- git/refs/symbolic.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/git/refs/symbolic.py b/git/refs/symbolic.py index 65bad6e48..4713e0c42 100644 --- a/git/refs/symbolic.py +++ b/git/refs/symbolic.py @@ -289,7 +289,8 @@ def _get_reference(self): 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) -> Union[Commit_ish, '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 @@ -330,7 +331,7 @@ def set_reference(self, ref, logmsg=None): 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 @@ -359,8 +360,8 @@ def set_reference(self, ref, logmsg=None): return self # aliased reference - reference = property(_get_reference, set_reference, doc="Returns the Reference we point to") - ref: Union['Reference'] = reference # type: ignore + reference = property(_get_reference, set_reference, doc="Returns the Reference we point to") # type: ignore + ref: Union['Reference'] = reference # type: ignore def is_valid(self) -> bool: """ From f2012e599e388580bf8823a23ff63a201e0bf4c4 Mon Sep 17 00:00:00 2001 From: Yobmod Date: Sat, 31 Jul 2021 17:25:46 +0100 Subject: [PATCH 07/23] Add type to symbolicreference.set_object() --- git/refs/reference.py | 4 ++-- git/refs/symbolic.py | 14 ++++++++------ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/git/refs/reference.py b/git/refs/reference.py index bc2c6e807..539691e72 100644 --- a/git/refs/reference.py +++ b/git/refs/reference.py @@ -63,8 +63,8 @@ def __str__(self) -> str: #{ 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 4713e0c42..0d2c98297 100644 --- a/git/refs/symbolic.py +++ b/git/refs/symbolic.py @@ -221,7 +221,8 @@ def _get_commit(self): # 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 @@ -250,7 +251,8 @@ def set_commit(self, commit: Union[Commit, 'SymbolicReference', str], logmsg=Non 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 @@ -277,10 +279,10 @@ def set_object(self, object, logmsg=None): # @ReservedAssignment # 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) -> 'SymbolicReference': """: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""" @@ -290,7 +292,7 @@ def _get_reference(self): return self.from_path(self.repo, target_ref_path) def set_reference(self, ref: Union[Commit_ish, 'SymbolicReference', str], - logmsg: Union[str, None] = None) -> Union[Commit_ish, 'SymbolicReference']: + 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 From d4d46697a6ce23edba8e22030916dad28d42abc2 Mon Sep 17 00:00:00 2001 From: Yobmod Date: Sat, 31 Jul 2021 17:29:06 +0100 Subject: [PATCH 08/23] cleanup --- git/refs/reference.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git/refs/reference.py b/git/refs/reference.py index 539691e72..a3647fb3b 100644 --- a/git/refs/reference.py +++ b/git/refs/reference.py @@ -7,7 +7,7 @@ # 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: From 13b38ce012dc1bf84d9dca8d141dcab86c0d4e09 Mon Sep 17 00:00:00 2001 From: Yobmod Date: Sat, 31 Jul 2021 17:49:18 +0100 Subject: [PATCH 09/23] Add type to symbolicreference.reference() --- git/refs/head.py | 1 + git/refs/symbolic.py | 14 +++++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/git/refs/head.py b/git/refs/head.py index 260bf5e7e..160272049 100644 --- a/git/refs/head.py +++ b/git/refs/head.py @@ -40,6 +40,7 @@ def __init__(self, repo: 'Repo', path: PathLike = _HEAD_NAME): raise ValueError("HEAD instance must point to %r, got %r" % (self._HEAD_NAME, path)) super(HEAD, self).__init__(repo, path) self.commit: 'Commit' + self.ref: 'Head' def orig_head(self) -> SymbolicReference: """ diff --git a/git/refs/symbolic.py b/git/refs/symbolic.py index 0d2c98297..5ce74938c 100644 --- a/git/refs/symbolic.py +++ b/git/refs/symbolic.py @@ -65,6 +65,7 @@ class SymbolicReference(object): def __init__(self, repo: 'Repo', path: PathLike, check_path: bool = False): self.repo = repo self.path = path + self.ref = self.reference def __str__(self) -> str: return str(self.path) @@ -282,7 +283,7 @@ def set_object(self, object: Union[Commit_ish, 'SymbolicReference', str], logmsg 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) -> 'SymbolicReference': + 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""" @@ -362,8 +363,15 @@ def set_reference(self, ref: Union[Commit_ish, 'SymbolicReference', str], return self # aliased reference - reference = property(_get_reference, set_reference, doc="Returns the Reference we point to") # type: ignore - ref: Union['Reference'] = reference # type: ignore + # reference = property(_get_reference, set_reference, doc="Returns the Reference we point to") # type: ignore + + @property + def reference(self) -> 'Reference': + return self._get_reference() + + @reference.setter + def reference(self, *args, **kwargs): + return self.set_reference(*args, **kwargs) def is_valid(self) -> bool: """ From 3be955e5adc09d20a7e2e919ee1e95a7a0f5fb0e Mon Sep 17 00:00:00 2001 From: Yobmod Date: Sat, 31 Jul 2021 17:53:44 +0100 Subject: [PATCH 10/23] Add type to symbolicreference.references() --- git/refs/head.py | 1 - git/refs/symbolic.py | 14 +++----------- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/git/refs/head.py b/git/refs/head.py index 160272049..260bf5e7e 100644 --- a/git/refs/head.py +++ b/git/refs/head.py @@ -40,7 +40,6 @@ def __init__(self, repo: 'Repo', path: PathLike = _HEAD_NAME): raise ValueError("HEAD instance must point to %r, got %r" % (self._HEAD_NAME, path)) super(HEAD, self).__init__(repo, path) self.commit: 'Commit' - self.ref: 'Head' def orig_head(self) -> SymbolicReference: """ diff --git a/git/refs/symbolic.py b/git/refs/symbolic.py index 5ce74938c..ae391c1e2 100644 --- a/git/refs/symbolic.py +++ b/git/refs/symbolic.py @@ -26,7 +26,7 @@ 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 @@ -65,7 +65,6 @@ class SymbolicReference(object): def __init__(self, repo: 'Repo', path: PathLike, check_path: bool = False): self.repo = repo self.path = path - self.ref = self.reference def __str__(self) -> str: return str(self.path) @@ -363,15 +362,8 @@ def set_reference(self, ref: Union[Commit_ish, 'SymbolicReference', str], return self # aliased reference - # reference = property(_get_reference, set_reference, doc="Returns the Reference we point to") # type: ignore - - @property - def reference(self) -> 'Reference': - return self._get_reference() - - @reference.setter - def reference(self, *args, **kwargs): - return self.set_reference(*args, **kwargs) + 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) -> bool: """ From 62f78814206a99fafeedab1d4f2ee6f4c6b70ef1 Mon Sep 17 00:00:00 2001 From: Yobmod Date: Sat, 31 Jul 2021 17:59:14 +0100 Subject: [PATCH 11/23] Add type to repo.base._to_full_tag_path --- git/repo/base.py | 13 +++++++------ pyproject.toml | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/git/repo/base.py b/git/repo/base.py index 355f93999..5581233ba 100644 --- a/git/repo/base.py +++ b/git/repo/base.py @@ -412,13 +412,14 @@ def tag(self, path: PathLike) -> TagReference: 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/pyproject.toml b/pyproject.toml index 6437a7199..4751ffcb9 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 From ef48a3513d7a9456fd57f4da248a9c73f9e668bd Mon Sep 17 00:00:00 2001 From: Yobmod Date: Sat, 31 Jul 2021 18:01:01 +0100 Subject: [PATCH 12/23] Add type to refs.head.delete() --- git/refs/head.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/git/refs/head.py b/git/refs/head.py index 260bf5e7e..56a87182f 100644 --- a/git/refs/head.py +++ b/git/refs/head.py @@ -21,7 +21,7 @@ __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" From e364c5e327f916366e5936aa2c9f3f4065aec034 Mon Sep 17 00:00:00 2001 From: Yobmod Date: Sat, 31 Jul 2021 18:02:06 +0100 Subject: [PATCH 13/23] Add type to refs.log._read_from_file() --- git/refs/log.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git/refs/log.py b/git/refs/log.py index 643b41140..ddd78bc76 100644 --- a/git/refs/log.py +++ b/git/refs/log.py @@ -157,7 +157,7 @@ def __init__(self, filepath: Union[PathLike, None] = None): 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) From 35231dba2f12ef4d19eabc409e72f773a19a3c43 Mon Sep 17 00:00:00 2001 From: Yobmod Date: Sat, 31 Jul 2021 18:04:28 +0100 Subject: [PATCH 14/23] Add type to objects.base.new() --- git/objects/base.py | 3 ++- pyproject.toml | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/git/objects/base.py b/git/objects/base.py index 64f105ca5..a3b0f230a 100644 --- a/git/objects/base.py +++ b/git/objects/base.py @@ -25,6 +25,7 @@ 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 @@ def __init__(self, repo: 'Repo', binsha: bytes): 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/pyproject.toml b/pyproject.toml index 4751ffcb9..ccf5c165d 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 From d6e736922cb69cc87dd6595ef93f247ce99a960a Mon Sep 17 00:00:00 2001 From: Yobmod Date: Sat, 31 Jul 2021 18:56:09 +0100 Subject: [PATCH 15/23] Add final types to config.py --- git/config.py | 18 +++++++++++------- git/util.py | 8 ++++---- pyproject.toml | 2 +- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/git/config.py b/git/config.py index ad02b4373..a3f41c60f 100644 --- a/git/config.py +++ b/git/config.py @@ -40,6 +40,7 @@ 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 @@ 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 @@ def __new__(cls, name: str, bases: TBD, clsdict: Dict[str, Any]) -> TBD: 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 @@ def __enter__(self) -> 'GitConfigParser': 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 @@ def read(self) -> None: # type: ignore[override] 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/util.py b/git/util.py index c0c0ecb73..92d95379e 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 @@ def __delitem__(self, index: Union[SupportsIndex, int, slice, str]) -> None: 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 @@ def list_items(cls, repo, *args, **kwargs): :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 ccf5c165d..6437a7199 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 From 476f4de6aa893bc0289c345a7d06b85256ab98bc Mon Sep 17 00:00:00 2001 From: Yobmod Date: Sat, 31 Jul 2021 19:00:23 +0100 Subject: [PATCH 16/23] Add set_dirty_and_flush_changes() types to config.py --- git/config.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/git/config.py b/git/config.py index a3f41c60f..011d0e0b1 100644 --- a/git/config.py +++ b/git/config.py @@ -102,7 +102,7 @@ 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: GitConfigParser, *args: Any, **kwargs: Any) -> _T: + def assure_data_present(self: 'GitConfigParser', *args: Any, **kwargs: Any) -> _T: self.read() return func(self, *args, **kwargs) # END wrapper method @@ -114,7 +114,7 @@ def set_dirty_and_flush_changes(non_const_func: Callable[..., _T]) -> Callable[. If so, the instance will be set dirty. Additionally, we flush the changes right to disk""" - def flush_changes(self: GitConfigParser, *args: Any, **kwargs: Any) -> _T: + def flush_changes(self: 'GitConfigParser', *args: Any, **kwargs: Any) -> _T: rval = non_const_func(self, *args, **kwargs) self._dirty = True self.write() From e6bee43b97862182d6c30bc8200f6abd1ff759e5 Mon Sep 17 00:00:00 2001 From: Yobmod Date: Sat, 31 Jul 2021 19:08:29 +0100 Subject: [PATCH 17/23] Add final types to commit.py --- git/objects/commit.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/git/objects/commit.py b/git/objects/commit.py index 9d7096563..b689167f5 100644 --- a/git/objects/commit.py +++ b/git/objects/commit.py @@ -282,7 +282,7 @@ def iter_items(cls, repo: 'Repo', rev: Union[str, 'Commit', 'SymbolicReference'] 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 @@ def _iter_from_process_or_stream(cls, repo: 'Repo', proc_or_stream: Union[Popen, 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 @@ def create_from_tree(cls, repo: 'Repo', tree: Union[Tree, str], message: str, 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 From 2fc8a461017db70051e12746468585479c081bec Mon Sep 17 00:00:00 2001 From: Yobmod Date: Sat, 31 Jul 2021 19:12:14 +0100 Subject: [PATCH 18/23] Add final types to tree.py --- git/objects/tree.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/git/objects/tree.py b/git/objects/tree.py index 70f36af5d..0cceb59ac 100644 --- a/git/objects/tree.py +++ b/git/objects/tree.py @@ -375,8 +375,8 @@ def __contains__(self, item: Union[IndexObjUnion, PathLike]) -> bool: # 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 From 9e5574ca26b30a9b5ec1e4763a590093e3dcfc97 Mon Sep 17 00:00:00 2001 From: Yobmod Date: Sat, 31 Jul 2021 19:25:38 +0100 Subject: [PATCH 19/23] Add final types to submodule.py --- git/objects/submodule/base.py | 13 +++++++------ git/objects/util.py | 12 ++++++------ pyproject.toml | 2 +- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/git/objects/submodule/base.py b/git/objects/submodule/base.py index 143511909..559d2585e 100644 --- a/git/objects/submodule/base.py +++ b/git/objects/submodule/base.py @@ -57,6 +57,7 @@ if TYPE_CHECKING: from git.index import IndexFile from git.repo import Repo + from git.refs import Head # ----------------------------------------------------------------------------- @@ -265,7 +266,7 @@ def _module_abspath(cls, parent_repo: 'Repo', path: PathLike, name: str) -> Path # 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 @@ def _clone_repo(cls, repo, url, path, name, **kwargs): 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 @@ def add(cls, repo: 'Repo', name: str, path: PathLike, url: Union[str, None] = No 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 @@ def update(self, recursive: bool = False, init: bool = True, to_latest_revision: 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 @@ def move(self, module_path, configuration=True, module=True): 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 @@ def exists(self) -> bool: # 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/util.py b/git/objects/util.py index db7807c26..f627211ec 100644 --- a/git/objects/util.py +++ b/git/objects/util.py @@ -144,20 +144,20 @@ def __init__(self, secs_west_of_utc: float, name: Union[None, str] = None) -> No 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 @@ def list_traverse(self, *args: Any, **kwargs: Any) -> Any: 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/pyproject.toml b/pyproject.toml index 6437a7199..4751ffcb9 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 From 56f8dd6a902736cb6b87329542ea6dcbf380884e Mon Sep 17 00:00:00 2001 From: Yobmod Date: Sat, 31 Jul 2021 20:05:53 +0100 Subject: [PATCH 20/23] Add final types to cmd.py --- git/cmd.py | 53 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/git/cmd.py b/git/cmd.py index 4404981e0..f82127453 100644 --- a/git/cmd.py +++ b/git/cmd.py @@ -39,10 +39,10 @@ # 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 @@ def wait(self, stderr: Union[None, bytes] = b'') -> int: 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 @@ def _kill_process(pid: int) -> None: 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 '' # end @@ -932,10 +935,10 @@ def as_text(stdout_value): 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 @@ def update_environment(self, **kwargs): 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. @@ -1043,6 +1046,13 @@ def _call_process(self, method: str, *args: None, **kwargs: None ) -> str: ... # 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 @@ def _prepare_ref(self, ref: AnyStr) -> bytes: 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 @@ def _get_persistent_cmd(self, attr_name: str, cmd_name: str, *args: Any, **kwarg 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 @@ def stream_object_data(self, ref: str) -> Tuple[str, str, int, 'Git.CatFileConte :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. From 48f64bbdea658fd9e0bd5d3d51c54ee6be8c05bd Mon Sep 17 00:00:00 2001 From: Yobmod Date: Sat, 31 Jul 2021 20:06:59 +0100 Subject: [PATCH 21/23] Add final types to index/fun.py --- git/index/fun.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git/index/fun.py b/git/index/fun.py index 49e3f2c52..16ec744e2 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 From 3c2454d20ba60e3350f3da103d5c1570ccc41c6f Mon Sep 17 00:00:00 2001 From: Yobmod Date: Sat, 31 Jul 2021 20:10:29 +0100 Subject: [PATCH 22/23] Add final types to symbolic.py --- git/refs/symbolic.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/git/refs/symbolic.py b/git/refs/symbolic.py index ae391c1e2..bcd3d261c 100644 --- a/git/refs/symbolic.py +++ b/git/refs/symbolic.py @@ -146,13 +146,13 @@ def dereference_recursive(cls, repo: 'Repo', ref_path: PathLike) -> str: 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) + hexsha, ref_path = cls._get_ref_info(repo, ref_path) # type: ignore if hexsha is not None: return hexsha # 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: PathLike) -> 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""" @@ -191,13 +191,13 @@ def _get_ref_info_helper(cls, repo: 'Repo', ref_path: PathLike): 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: PathLike) -> 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 @@ -206,7 +206,7 @@ def _get_object(self): # 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 From 2a350b57ce79a0e1b71623d1146c52918232e074 Mon Sep 17 00:00:00 2001 From: Yobmod Date: Sat, 31 Jul 2021 20:18:20 +0100 Subject: [PATCH 23/23] Add final final types to symbolic.py --- git/refs/symbolic.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/git/refs/symbolic.py b/git/refs/symbolic.py index bcd3d261c..b4a933aa7 100644 --- a/git/refs/symbolic.py +++ b/git/refs/symbolic.py @@ -40,7 +40,7 @@ __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']: @@ -140,26 +140,28 @@ def _iter_packed_refs(cls, repo: 'Repo') -> Iterator[Tuple[str, str]]: # 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) # type: ignore + hexsha, ref_path = cls._get_ref_info(repo, ref_path) if hexsha is not None: return hexsha # END recursive dereferencing @classmethod - def _get_ref_info_helper(cls, repo: 'Repo', ref_path: PathLike) -> Union[Tuple[str, None], Tuple[None, str]]: + 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 @@ -191,7 +193,7 @@ def _get_ref_info_helper(cls, repo: 'Repo', ref_path: PathLike) -> Union[Tuple[s raise ValueError("Failed to parse reference information from %r" % ref_path) @classmethod - def _get_ref_info(cls, repo: 'Repo', ref_path: PathLike) -> Union[Tuple[str, None], Tuple[None, str]]: + 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"""