diff options
author | Yobmod <yobmod@gmail.com> | 2021-07-19 16:56:38 +0100 |
---|---|---|
committer | Yobmod <yobmod@gmail.com> | 2021-07-19 16:56:38 +0100 |
commit | 29e12e9ceee59a87984c9049ac84e030a4dd0ed2 (patch) | |
tree | e44684b17ffbb45aea16fc7de62b924718326cb2 /git/objects/util.py | |
parent | 44f0578f841c48bba6473e0890b8a3daae94c58e (diff) | |
download | gitpython-29e12e9ceee59a87984c9049ac84e030a4dd0ed2.tar.gz |
Make traversable and serilizable into protocols
Diffstat (limited to 'git/objects/util.py')
-rw-r--r-- | git/objects/util.py | 78 |
1 files changed, 54 insertions, 24 deletions
diff --git a/git/objects/util.py b/git/objects/util.py index fbe3d9de..04af3b83 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 @@ -289,7 +291,8 @@ class ProcessStreamAdapter(object): 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: + """ """ + 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 @@ -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 )) |