summaryrefslogtreecommitdiff
path: root/git/objects
diff options
context:
space:
mode:
authorSebastian Thiel <sebastian.thiel@icloud.com>2021-07-20 07:04:18 +0800
committerGitHub <noreply@github.com>2021-07-20 07:04:18 +0800
commitcfd653aeeb3cb807f2cd2ae9fff5568880ac67da (patch)
tree8514389e82efdcdcdeaab5d3a85553883f28117c /git/objects
parentacbd6bad9ded9a1d59e80e71d334d64b0244f5cd (diff)
parent600df043e76924d43a4f9f88f4e3241740f34c77 (diff)
downloadgitpython-cfd653aeeb3cb807f2cd2ae9fff5568880ac67da.tar.gz
Merge pull request #1295 from Yobmod/main
Add types to refs
Diffstat (limited to 'git/objects')
-rw-r--r--git/objects/__init__.py2
-rw-r--r--git/objects/base.py6
-rw-r--r--git/objects/blob.py4
-rw-r--r--git/objects/commit.py21
-rw-r--r--git/objects/fun.py2
-rw-r--r--git/objects/submodule/base.py7
-rw-r--r--git/objects/tag.py8
-rw-r--r--git/objects/tree.py14
-rw-r--r--git/objects/util.py82
9 files changed, 91 insertions, 55 deletions
diff --git a/git/objects/__init__.py b/git/objects/__init__.py
index 897eb98f..1d0bb7a5 100644
--- a/git/objects/__init__.py
+++ b/git/objects/__init__.py
@@ -2,8 +2,6 @@
Import all submodules main classes into the package space
"""
# flake8: noqa
-from __future__ import absolute_import
-
import inspect
from .base import *
diff --git a/git/objects/base.py b/git/objects/base.py
index 4e2ed493..64f105ca 100644
--- a/git/objects/base.py
+++ b/git/objects/base.py
@@ -15,9 +15,9 @@ from .util import get_object_type_by_name
# typing ------------------------------------------------------------------
-from typing import Any, TYPE_CHECKING, Optional, Union
+from typing import Any, TYPE_CHECKING, Union
-from git.types import PathLike, Commit_ish
+from git.types import PathLike, Commit_ish, Lit_commit_ish
if TYPE_CHECKING:
from git.repo import Repo
@@ -44,7 +44,7 @@ class Object(LazyMixin):
TYPES = (dbtyp.str_blob_type, dbtyp.str_tree_type, dbtyp.str_commit_type, dbtyp.str_tag_type)
__slots__ = ("repo", "binsha", "size")
- type = None # type: Optional[str] # to be set by subclass
+ type: Union[Lit_commit_ish, None] = None
def __init__(self, repo: 'Repo', binsha: bytes):
"""Initialize an object by identifying it by its binary sha.
diff --git a/git/objects/blob.py b/git/objects/blob.py
index 017178f0..99b5c636 100644
--- a/git/objects/blob.py
+++ b/git/objects/blob.py
@@ -6,6 +6,8 @@
from mimetypes import guess_type
from . import base
+from git.types import Literal
+
__all__ = ('Blob', )
@@ -13,7 +15,7 @@ class Blob(base.IndexObject):
"""A Blob encapsulates a git blob object"""
DEFAULT_MIME_TYPE = "text/plain"
- type = "blob"
+ type: Literal['blob'] = "blob"
# valid blob modes
executable_mode = 0o100755
diff --git a/git/objects/commit.py b/git/objects/commit.py
index 65a87591..11cf52a5 100644
--- a/git/objects/commit.py
+++ b/git/objects/commit.py
@@ -41,10 +41,11 @@ import logging
from typing import Any, IO, Iterator, List, Sequence, Tuple, Union, TYPE_CHECKING
-from git.types import PathLike, TypeGuard
+from git.types import PathLike, TypeGuard, Literal
if TYPE_CHECKING:
from git.repo import Repo
+ from git.refs import SymbolicReference
# ------------------------------------------------------------------------
@@ -73,14 +74,14 @@ class Commit(base.Object, TraversableIterableObj, Diffable, Serializable):
default_encoding = "UTF-8"
# object configuration
- type = "commit"
+ type: Literal['commit'] = "commit"
__slots__ = ("tree",
"author", "authored_date", "author_tz_offset",
"committer", "committed_date", "committer_tz_offset",
"message", "parents", "encoding", "gpgsig")
_id_attribute_ = "hexsha"
- def __init__(self, repo: 'Repo', binsha: bytes, tree: Union['Tree', None] = None,
+ def __init__(self, repo: 'Repo', binsha: bytes, tree: Union[Tree, None] = None,
author: Union[Actor, None] = None,
authored_date: Union[int, None] = None,
author_tz_offset: Union[None, float] = None,
@@ -201,11 +202,11 @@ class Commit(base.Object, TraversableIterableObj, Diffable, Serializable):
# END handle attrs
@property
- def authored_datetime(self) -> 'datetime.datetime':
+ def authored_datetime(self) -> datetime.datetime:
return from_timestamp(self.authored_date, self.author_tz_offset)
@property
- def committed_datetime(self) -> 'datetime.datetime':
+ def committed_datetime(self) -> datetime.datetime:
return from_timestamp(self.committed_date, self.committer_tz_offset)
@property
@@ -242,7 +243,7 @@ class Commit(base.Object, TraversableIterableObj, Diffable, Serializable):
return self.repo.git.name_rev(self)
@classmethod
- def iter_items(cls, repo: 'Repo', rev: str, # type: ignore
+ def iter_items(cls, repo: 'Repo', rev: Union[str, 'Commit', 'SymbolicReference'], # type: ignore
paths: Union[PathLike, Sequence[PathLike]] = '', **kwargs: Any
) -> Iterator['Commit']:
"""Find all commits matching the given criteria.
@@ -354,7 +355,7 @@ class Commit(base.Object, TraversableIterableObj, Diffable, Serializable):
finalize_process(proc_or_stream)
@ classmethod
- def create_from_tree(cls, repo: 'Repo', tree: Union['Tree', str], message: str,
+ 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):
@@ -516,8 +517,10 @@ class Commit(base.Object, TraversableIterableObj, Diffable, Serializable):
return self
def _deserialize(self, stream: BytesIO) -> 'Commit':
- """:param from_rev_list: if true, the stream format is coming from the rev-list command
- Otherwise it is assumed to be a plain data stream from our object"""
+ """
+ :param from_rev_list: if true, the stream format is coming from the rev-list command
+ Otherwise it is assumed to be a plain data stream from our object
+ """
readline = stream.readline
self.tree = Tree(self.repo, hex_to_bin(readline().split()[1]), Tree.tree_id << 12, '')
diff --git a/git/objects/fun.py b/git/objects/fun.py
index fc2ea1e7..d6cdafe1 100644
--- a/git/objects/fun.py
+++ b/git/objects/fun.py
@@ -167,7 +167,7 @@ def traverse_trees_recursive(odb: 'GitCmdObjectDB', tree_shas: Sequence[Union[by
data: List[EntryTupOrNone] = []
else:
# make new list for typing as list invariant
- data = [x for x in tree_entries_from_data(odb.stream(tree_sha).read())]
+ data = list(tree_entries_from_data(odb.stream(tree_sha).read()))
# END handle muted trees
trees_data.append(data)
# END for each sha to get data for
diff --git a/git/objects/submodule/base.py b/git/objects/submodule/base.py
index b485dbf6..d5ba118f 100644
--- a/git/objects/submodule/base.py
+++ b/git/objects/submodule/base.py
@@ -52,7 +52,7 @@ from .util import (
from typing import Callable, Dict, Mapping, Sequence, TYPE_CHECKING, cast
from typing import Any, Iterator, Union
-from git.types import Commit_ish, PathLike, TBD
+from git.types import Commit_ish, Literal, PathLike, TBD
if TYPE_CHECKING:
from git.index import IndexFile
@@ -105,7 +105,7 @@ class Submodule(IndexObject, TraversableIterableObj):
k_default_mode = stat.S_IFDIR | stat.S_IFLNK # submodules are directories with link-status
# this is a bogus type for base class compatibility
- type = 'submodule'
+ type: Literal['submodule'] = 'submodule' # type: ignore
__slots__ = ('_parent_commit', '_url', '_branch_path', '_name', '__weakref__')
_cache_attrs = ('path', '_url', '_branch_path')
@@ -475,7 +475,8 @@ class Submodule(IndexObject, TraversableIterableObj):
sm._branch_path = br.path
# we deliberately assume that our head matches our index !
- sm.binsha = mrepo.head.commit.binsha # type: ignore
+ if mrepo:
+ sm.binsha = mrepo.head.commit.binsha
index.add([sm], write=True)
return sm
diff --git a/git/objects/tag.py b/git/objects/tag.py
index cb6efbe9..7048eb40 100644
--- a/git/objects/tag.py
+++ b/git/objects/tag.py
@@ -11,6 +11,8 @@ from ..compat import defenc
from typing import List, TYPE_CHECKING, Union
+from git.types import Literal
+
if TYPE_CHECKING:
from git.repo import Repo
from git.util import Actor
@@ -24,7 +26,7 @@ __all__ = ("TagObject", )
class TagObject(base.Object):
"""Non-Lightweight tag carrying additional information about an object we are pointing to."""
- type = "tag"
+ type: Literal['tag'] = "tag"
__slots__ = ("object", "tag", "tagger", "tagged_date", "tagger_tz_offset", "message")
def __init__(self, repo: 'Repo', binsha: bytes,
@@ -49,7 +51,7 @@ class TagObject(base.Object):
authored_date is in, in a format similar to time.altzone"""
super(TagObject, self).__init__(repo, binsha)
if object is not None:
- self.object = object # type: Union['Commit', 'Blob', 'Tree', 'TagObject']
+ self.object: Union['Commit', 'Blob', 'Tree', 'TagObject'] = object
if tag is not None:
self.tag = tag
if tagger is not None:
@@ -65,7 +67,7 @@ class TagObject(base.Object):
"""Cache all our attributes at once"""
if attr in TagObject.__slots__:
ostream = self.repo.odb.stream(self.binsha)
- lines = ostream.read().decode(defenc, 'replace').splitlines() # type: List[str]
+ lines: List[str] = ostream.read().decode(defenc, 'replace').splitlines()
_obj, hexsha = lines[0].split(" ")
_type_token, type_name = lines[1].split(" ")
diff --git a/git/objects/tree.py b/git/objects/tree.py
index a9656c1d..dd1fe783 100644
--- a/git/objects/tree.py
+++ b/git/objects/tree.py
@@ -24,7 +24,7 @@ from .fun import (
from typing import (Any, Callable, Dict, Iterable, Iterator, List,
Tuple, Type, Union, cast, TYPE_CHECKING)
-from git.types import PathLike, TypeGuard
+from git.types import PathLike, TypeGuard, Literal
if TYPE_CHECKING:
from git.repo import Repo
@@ -195,7 +195,7 @@ class Tree(IndexObject, git_diff.Diffable, util.Traversable, util.Serializable):
blob = tree[0]
"""
- type = "tree"
+ type: Literal['tree'] = "tree"
__slots__ = "_cache"
# actual integer ids for comparison
@@ -285,7 +285,7 @@ class Tree(IndexObject, git_diff.Diffable, util.Traversable, util.Serializable):
return [i for i in self if i.type == "tree"]
@ property
- def blobs(self) -> List['Blob']:
+ def blobs(self) -> List[Blob]:
""":return: list(Blob, ...) list of blobs directly below this tree"""
return [i for i in self if i.type == "blob"]
@@ -298,7 +298,7 @@ class Tree(IndexObject, git_diff.Diffable, util.Traversable, util.Serializable):
See the ``TreeModifier`` for more information on how to alter the cache"""
return TreeModifier(self._cache)
- def traverse(self, # type: ignore # overrides super()
+ def traverse(self, # type: ignore[override]
predicate: Callable[[Union[IndexObjUnion, TraversedTreeTup], int], bool] = lambda i, d: True,
prune: Callable[[Union[IndexObjUnion, TraversedTreeTup], int], bool] = lambda i, d: False,
depth: int = -1,
@@ -322,8 +322,8 @@ class Tree(IndexObject, git_diff.Diffable, util.Traversable, util.Serializable):
# assert is_tree_traversed(ret_tup), f"Type is {[type(x) for x in list(ret_tup[0])]}"
# return ret_tup[0]"""
return cast(Union[Iterator[IndexObjUnion], Iterator[TraversedTreeTup]],
- super(Tree, self).traverse(predicate, prune, depth, # type: ignore
- branch_first, visit_once, ignore_self))
+ super(Tree, self)._traverse(predicate, prune, depth, # type: ignore
+ branch_first, visit_once, ignore_self))
def list_traverse(self, *args: Any, **kwargs: Any) -> IterableList[IndexObjUnion]:
"""
@@ -331,7 +331,7 @@ class Tree(IndexObject, git_diff.Diffable, util.Traversable, util.Serializable):
traverse()
Tree -> IterableList[Union['Submodule', 'Tree', 'Blob']]
"""
- return super(Tree, self).list_traverse(* args, **kwargs)
+ return super(Tree, self)._list_traverse(* args, **kwargs)
# List protocol
diff --git a/git/objects/util.py b/git/objects/util.py
index fbe3d9de..ef1ae77b 100644
--- a/git/objects/util.py
+++ b/git/objects/util.py
@@ -5,6 +5,8 @@
# the BSD License: http://www.opensource.org/licenses/bsd-license.php
"""Module for general utility functions"""
+from abc import abstractmethod
+import warnings
from git.util import (
IterableList,
IterableObj,
@@ -23,7 +25,7 @@ from datetime import datetime, timedelta, tzinfo
from typing import (Any, Callable, Deque, Iterator, NamedTuple, overload, Sequence,
TYPE_CHECKING, Tuple, Type, TypeVar, Union, cast)
-from git.types import Has_id_attribute, Literal
+from git.types import Has_id_attribute, Literal, Protocol, runtime_checkable
if TYPE_CHECKING:
from io import BytesIO, StringIO
@@ -283,13 +285,14 @@ class ProcessStreamAdapter(object):
def __init__(self, process: 'Popen', stream_name: str) -> None:
self._proc = process
- self._stream = getattr(process, stream_name) # type: StringIO ## guess
+ self._stream: StringIO = getattr(process, stream_name) # guessed type
def __getattr__(self, attr: str) -> Any:
return getattr(self._stream, attr)
-class Traversable(object):
+@runtime_checkable
+class Traversable(Protocol):
"""Simple interface to perform depth-first or breadth-first traversals
into one direction.
@@ -301,6 +304,7 @@ class Traversable(object):
__slots__ = ()
@classmethod
+ @abstractmethod
def _get_intermediate_items(cls, item) -> Sequence['Traversable']:
"""
Returns:
@@ -313,7 +317,18 @@ class Traversable(object):
"""
raise NotImplementedError("To be implemented in subclass")
- def list_traverse(self, *args: Any, **kwargs: Any) -> IterableList[Union['Commit', 'Submodule', 'Tree', 'Blob']]:
+ @abstractmethod
+ def list_traverse(self, *args: Any, **kwargs: Any) -> Any:
+ """ """
+ warnings.warn("list_traverse() method should only be called from subclasses."
+ "Calling from Traversable abstract class will raise NotImplementedError in 3.1.20"
+ "Builtin sublclasses are 'Submodule', 'Tree' and 'Commit",
+ DeprecationWarning,
+ stacklevel=2)
+ return self._list_traverse(*args, **kwargs)
+
+ def _list_traverse(self, as_edge=False, *args: Any, **kwargs: Any
+ ) -> IterableList[Union['Commit', 'Submodule', 'Tree', 'Blob']]:
"""
:return: IterableList with the results of the traversal as produced by
traverse()
@@ -329,22 +344,34 @@ class Traversable(object):
id = "" # shouldn't reach here, unless Traversable subclass created with no _id_attribute_
# could add _id_attribute_ to Traversable, or make all Traversable also Iterable?
- out: IterableList[Union['Commit', 'Submodule', 'Tree', 'Blob']] = IterableList(id)
- # overloads in subclasses (mypy does't allow typing self: subclass)
- # Union[IterableList['Commit'], IterableList['Submodule'], IterableList[Union['Submodule', 'Tree', 'Blob']]]
-
- # NOTE: if is_edge=True, self.traverse returns a Tuple, so should be prevented or flattened?
- kwargs['as_edge'] = False
- out.extend(self.traverse(*args, **kwargs)) # type: ignore
- return out
-
- def traverse(self,
- predicate: Callable[[Union['Traversable', 'Blob', TraversedTup], int], bool] = lambda i, d: True,
- prune: Callable[[Union['Traversable', 'Blob', TraversedTup], int], bool] = lambda i, d: False,
- depth: int = -1, branch_first: bool = True, visit_once: bool = True,
- ignore_self: int = 1, as_edge: bool = False
- ) -> Union[Iterator[Union['Traversable', 'Blob']],
- Iterator[TraversedTup]]:
+ if not as_edge:
+ out: IterableList[Union['Commit', 'Submodule', 'Tree', 'Blob']] = IterableList(id)
+ out.extend(self.traverse(as_edge=as_edge, *args, **kwargs)) # type: ignore
+ return out
+ # overloads in subclasses (mypy does't allow typing self: subclass)
+ # Union[IterableList['Commit'], IterableList['Submodule'], IterableList[Union['Submodule', 'Tree', 'Blob']]]
+ else:
+ # Raise deprecationwarning, doesn't make sense to use this
+ out_list: IterableList = IterableList(self.traverse(*args, **kwargs))
+ return out_list
+
+ @ abstractmethod
+ def traverse(self, *args: Any, **kwargs: Any) -> Any:
+ """ """
+ warnings.warn("traverse() method should only be called from subclasses."
+ "Calling from Traversable abstract class will raise NotImplementedError in 3.1.20"
+ "Builtin sublclasses are 'Submodule', 'Tree' and 'Commit",
+ DeprecationWarning,
+ stacklevel=2)
+ return self._traverse(*args, **kwargs)
+
+ def _traverse(self,
+ predicate: Callable[[Union['Traversable', 'Blob', TraversedTup], int], bool] = lambda i, d: True,
+ prune: Callable[[Union['Traversable', 'Blob', TraversedTup], int], bool] = lambda i, d: False,
+ depth: int = -1, branch_first: bool = True, visit_once: bool = True,
+ ignore_self: int = 1, as_edge: bool = False
+ ) -> Union[Iterator[Union['Traversable', 'Blob']],
+ Iterator[TraversedTup]]:
""":return: iterator yielding of items found when traversing self
:param predicate: f(i,d) returns False if item i at depth d should not be included in the result
@@ -387,7 +414,7 @@ class Traversable(object):
ignore_self=False is_edge=False -> Iterator[Tuple[src, item]]"""
visited = set()
- stack = deque() # type: Deque[TraverseNT]
+ stack: Deque[TraverseNT] = deque()
stack.append(TraverseNT(0, self, None)) # self is always depth level 0
def addToStack(stack: Deque[TraverseNT],
@@ -435,11 +462,13 @@ class Traversable(object):
# END for each item on work stack
-class Serializable(object):
+@ runtime_checkable
+class Serializable(Protocol):
"""Defines methods to serialize and deserialize objects from and into a data stream"""
__slots__ = ()
+ # @abstractmethod
def _serialize(self, stream: 'BytesIO') -> 'Serializable':
"""Serialize the data of this object into the given data stream
:note: a serialized object would ``_deserialize`` into the same object
@@ -447,6 +476,7 @@ class Serializable(object):
:return: self"""
raise NotImplementedError("To be implemented in subclass")
+ # @abstractmethod
def _deserialize(self, stream: 'BytesIO') -> 'Serializable':
"""Deserialize all information regarding this object from the stream
:param stream: a file-like object
@@ -454,13 +484,13 @@ class Serializable(object):
raise NotImplementedError("To be implemented in subclass")
-class TraversableIterableObj(Traversable, IterableObj):
+class TraversableIterableObj(IterableObj, Traversable):
__slots__ = ()
TIobj_tuple = Tuple[Union[T_TIobj, None], T_TIobj]
- def list_traverse(self: T_TIobj, *args: Any, **kwargs: Any) -> IterableList[T_TIobj]: # type: ignore[override]
- return super(TraversableIterableObj, self).list_traverse(* args, **kwargs)
+ def list_traverse(self: T_TIobj, *args: Any, **kwargs: Any) -> IterableList[T_TIobj]:
+ return super(TraversableIterableObj, self)._list_traverse(* args, **kwargs)
@ overload # type: ignore
def traverse(self: T_TIobj,
@@ -522,6 +552,6 @@ class TraversableIterableObj(Traversable, IterableObj):
"""
return cast(Union[Iterator[T_TIobj],
Iterator[Tuple[Union[None, T_TIobj], T_TIobj]]],
- super(TraversableIterableObj, self).traverse(
+ super(TraversableIterableObj, self)._traverse(
predicate, prune, depth, branch_first, visit_once, ignore_self, as_edge # type: ignore
))