55# the BSD License: http://www.opensource.org/licenses/bsd-license.php
66"""Module for general utility functions"""
77
8+ from abc import abstractmethod
9+ import warnings
810from git .util import (
911 IterableList ,
1012 IterableObj ,
2325from typing import (Any , Callable , Deque , Iterator , NamedTuple , overload , Sequence ,
2426 TYPE_CHECKING , Tuple , Type , TypeVar , Union , cast )
2527
26- from git .types import Has_id_attribute , Literal
28+ from git .types import Has_id_attribute , Literal , Protocol , runtime_checkable
2729
2830if TYPE_CHECKING :
2931 from io import BytesIO , StringIO
@@ -289,7 +291,8 @@ def __getattr__(self, attr: str) -> Any:
289291 return getattr (self ._stream , attr )
290292
291293
292- class Traversable (object ):
294+ @runtime_checkable
295+ class Traversable (Protocol ):
293296
294297 """Simple interface to perform depth-first or breadth-first traversals
295298 into one direction.
@@ -301,6 +304,7 @@ class Traversable(object):
301304 __slots__ = ()
302305
303306 @classmethod
307+ @abstractmethod
304308 def _get_intermediate_items (cls , item ) -> Sequence ['Traversable' ]:
305309 """
306310 Returns:
@@ -313,7 +317,18 @@ class Tree:: (cls, Tree) -> Tuple[Tree, ...]
313317 """
314318 raise NotImplementedError ("To be implemented in subclass" )
315319
316- def list_traverse (self , * args : Any , ** kwargs : Any ) -> IterableList [Union ['Commit' , 'Submodule' , 'Tree' , 'Blob' ]]:
320+ @abstractmethod
321+ def list_traverse (self , * args : Any , ** kwargs : Any ) -> Any :
322+ """ """
323+ warnings .warn ("list_traverse() method should only be called from subclasses."
324+ "Calling from Traversable abstract class will raise NotImplementedError in 3.1.20"
325+ "Builtin sublclasses are 'Submodule', 'Tree' and 'Commit" ,
326+ DeprecationWarning ,
327+ stacklevel = 2 )
328+ return self ._list_traverse (* args , ** kwargs )
329+
330+ def _list_traverse (self , as_edge = False , * args : Any , ** kwargs : Any
331+ ) -> IterableList [Union ['Commit' , 'Submodule' , 'Tree' , 'Blob' ]]:
317332 """
318333 :return: IterableList with the results of the traversal as produced by
319334 traverse()
@@ -329,22 +344,34 @@ def list_traverse(self, *args: Any, **kwargs: Any) -> IterableList[Union['Commit
329344 id = "" # shouldn't reach here, unless Traversable subclass created with no _id_attribute_
330345 # could add _id_attribute_ to Traversable, or make all Traversable also Iterable?
331346
332- out : IterableList [Union ['Commit' , 'Submodule' , 'Tree' , 'Blob' ]] = IterableList (id )
333- # overloads in subclasses (mypy does't allow typing self: subclass)
334- # Union[IterableList['Commit'], IterableList['Submodule'], IterableList[Union['Submodule', 'Tree', 'Blob']]]
335-
336- # NOTE: if is_edge=True, self.traverse returns a Tuple, so should be prevented or flattened?
337- kwargs ['as_edge' ] = False
338- out .extend (self .traverse (* args , ** kwargs )) # type: ignore
339- return out
340-
341- def traverse (self ,
342- predicate : Callable [[Union ['Traversable' , 'Blob' , TraversedTup ], int ], bool ] = lambda i , d : True ,
343- prune : Callable [[Union ['Traversable' , 'Blob' , TraversedTup ], int ], bool ] = lambda i , d : False ,
344- depth : int = - 1 , branch_first : bool = True , visit_once : bool = True ,
345- ignore_self : int = 1 , as_edge : bool = False
346- ) -> Union [Iterator [Union ['Traversable' , 'Blob' ]],
347- Iterator [TraversedTup ]]:
347+ if not as_edge :
348+ out : IterableList [Union ['Commit' , 'Submodule' , 'Tree' , 'Blob' ]] = IterableList (id )
349+ out .extend (self .traverse (as_edge = as_edge , * args , ** kwargs )) # type: ignore
350+ return out
351+ # overloads in subclasses (mypy does't allow typing self: subclass)
352+ # Union[IterableList['Commit'], IterableList['Submodule'], IterableList[Union['Submodule', 'Tree', 'Blob']]]
353+ else :
354+ # Raise deprecationwarning, doesn't make sense to use this
355+ out_list : IterableList = IterableList (self .traverse (* args , ** kwargs ))
356+ return out_list
357+
358+ @ abstractmethod
359+ def traverse (self , * args : Any , ** kwargs ) -> Any :
360+ """ """
361+ warnings .warn ("traverse() method should only be called from subclasses."
362+ "Calling from Traversable abstract class will raise NotImplementedError in 3.1.20"
363+ "Builtin sublclasses are 'Submodule', 'Tree' and 'Commit" ,
364+ DeprecationWarning ,
365+ stacklevel = 2 )
366+ return self ._traverse (* args , ** kwargs )
367+
368+ def _traverse (self ,
369+ predicate : Callable [[Union ['Traversable' , 'Blob' , TraversedTup ], int ], bool ] = lambda i , d : True ,
370+ prune : Callable [[Union ['Traversable' , 'Blob' , TraversedTup ], int ], bool ] = lambda i , d : False ,
371+ depth : int = - 1 , branch_first : bool = True , visit_once : bool = True ,
372+ ignore_self : int = 1 , as_edge : bool = False
373+ ) -> Union [Iterator [Union ['Traversable' , 'Blob' ]],
374+ Iterator [TraversedTup ]]:
348375 """:return: iterator yielding of items found when traversing self
349376 :param predicate: f(i,d) returns False if item i at depth d should not be included in the result
350377
@@ -435,32 +462,35 @@ def addToStack(stack: Deque[TraverseNT],
435462 # END for each item on work stack
436463
437464
438- class Serializable (object ):
465+ @ runtime_checkable
466+ class Serializable (Protocol ):
439467
440468 """Defines methods to serialize and deserialize objects from and into a data stream"""
441469 __slots__ = ()
442470
471+ # @abstractmethod
443472 def _serialize (self , stream : 'BytesIO' ) -> 'Serializable' :
444473 """Serialize the data of this object into the given data stream
445474 :note: a serialized object would ``_deserialize`` into the same object
446475 :param stream: a file-like object
447476 :return: self"""
448477 raise NotImplementedError ("To be implemented in subclass" )
449478
479+ # @abstractmethod
450480 def _deserialize (self , stream : 'BytesIO' ) -> 'Serializable' :
451481 """Deserialize all information regarding this object from the stream
452482 :param stream: a file-like object
453483 :return: self"""
454484 raise NotImplementedError ("To be implemented in subclass" )
455485
456486
457- class TraversableIterableObj (Traversable , IterableObj ):
487+ class TraversableIterableObj (IterableObj , Traversable ):
458488 __slots__ = ()
459489
460490 TIobj_tuple = Tuple [Union [T_TIobj , None ], T_TIobj ]
461491
462- def list_traverse (self : T_TIobj , * args : Any , ** kwargs : Any ) -> IterableList [T_TIobj ]: # type: ignore[override]
463- return super (TraversableIterableObj , self ).list_traverse (* args , ** kwargs )
492+ def list_traverse (self : T_TIobj , * args : Any , ** kwargs : Any ) -> IterableList [T_TIobj ]:
493+ return super (TraversableIterableObj , self )._list_traverse (* args , ** kwargs )
464494
465495 @ overload # type: ignore
466496 def traverse (self : T_TIobj ,
@@ -522,6 +552,6 @@ def is_commit_traversed(inp: Tuple) -> TypeGuard[Tuple[Iterator[Tuple['Commit',
522552 """
523553 return cast (Union [Iterator [T_TIobj ],
524554 Iterator [Tuple [Union [None , T_TIobj ], T_TIobj ]]],
525- super (TraversableIterableObj , self ).traverse (
555+ super (TraversableIterableObj , self )._traverse (
526556 predicate , prune , depth , branch_first , visit_once , ignore_self , as_edge # type: ignore
527557 ))
0 commit comments