1- from typing import Union
1+ """Traversal of a datastructure."""
2+ from typing import Union , Sequence , Iterable , Optional , Tuple , Type
23
34from odin .utils import getmeta
45
@@ -10,7 +11,13 @@ class NotSupplied:
1011 pass
1112
1213
13- def _split_atom (atom ):
14+ NotSuppliedType = Type [NotSupplied ]
15+ OptionalStr = Union [str , NotSuppliedType ]
16+ PathAtom = Tuple [OptionalStr , OptionalStr , str ]
17+
18+
19+ def _split_atom (atom : str ) -> PathAtom :
20+ """Split a section of a path into lookups that can be used to navigate a path."""
1421 if "[" in atom :
1522 field , _ , idx = atom .rstrip ("]" ).partition ("[" )
1623 return idx , NotSupplied , field
@@ -26,19 +33,23 @@ class TraversalPath:
2633 """A path through a resource structure."""
2734
2835 @classmethod
29- def parse (cls , path : Union ["TraversalPath" , str ]):
36+ def parse (cls , path : Union ["TraversalPath" , str ]) -> Optional ["TraversalPath" ]:
37+ """Parse a traversal path string."""
3038 if isinstance (path , TraversalPath ):
3139 return path
3240 if isinstance (path , str ):
3341 return cls (* [_split_atom (a ) for a in path .split ("." )])
3442
35- def __init__ (self , * path ):
43+ __slots__ = ("_path" ,)
44+
45+ def __init__ (self , * path : PathAtom ):
46+ """Initialise traversal path"""
3647 self ._path = path
3748
3849 def __repr__ (self ):
3950 return f"<TraversalPath: { self } >"
4051
41- def __str__ (self ):
52+ def __str__ (self ) -> str :
4253 atoms = []
4354 for value , key , field in self ._path :
4455 if value is NotSupplied :
@@ -49,15 +60,18 @@ def __str__(self):
4960 atoms .append (f"{ field } {{{ key } ={ value } }}" )
5061 return "." .join (atoms )
5162
52- def __hash__ (self ):
63+ def __hash__ (self ) -> int :
64+ """Hash of the path."""
5365 return hash (self ._path )
5466
55- def __eq__ (self , other ):
67+ def __eq__ (self , other ) -> bool :
68+ """Compare to another path."""
5669 if isinstance (other , TraversalPath ):
5770 return hash (self ) == hash (other )
5871 return NotImplemented
5972
60- def __add__ (self , other ):
73+ def __add__ (self , other ) -> "TraversalPath" :
74+ """Join paths together."""
6175 if isinstance (other , TraversalPath ):
6276 return TraversalPath (* (self ._path + other ._path ))
6377
@@ -69,7 +83,8 @@ def __add__(self, other):
6983
7084 raise TypeError (f"Cannot add '{ other } ' to a path." )
7185
72- def __iter__ (self ):
86+ def __iter__ (self ) -> Iterable [PathAtom ]:
87+ """Iterate a path returning each element on the path."""
7388 return iter (self ._path )
7489
7590 def get_value (self , root_resource : ResourceBase ):
@@ -126,7 +141,10 @@ class ResourceTraversalIterator:
126141
127142 """
128143
129- def __init__ (self , resource ):
144+ __slots__ = ("_resource_iters" , "_field_iters" , "_path" , "_resource_stack" )
145+
146+ def __init__ (self , resource : Union [ResourceBase , Sequence [ResourceBase ]]):
147+ """Initialise instance with the initial resource or sequence of resources."""
130148 if isinstance (resource , (list , tuple )):
131149 # Stack of resource iterators (starts initially with entries from the list)
132150 self ._resource_iters = [iter ([(i , r ) for i , r in enumerate (resource )])]
@@ -139,10 +157,12 @@ def __init__(self, resource):
139157 self ._path = [(NotSupplied , NotSupplied , NotSupplied )]
140158 self ._resource_stack = [None ]
141159
142- def __iter__ (self ):
160+ def __iter__ (self ) -> Iterable [ResourceBase ]:
161+ """Obtain an iterable instance."""
143162 return self
144163
145- def __next__ (self ):
164+ def __next__ (self ) -> ResourceBase :
165+ """Get next resource instance."""
146166 if self ._resource_iters :
147167 if self ._field_iters :
148168 # Check if the last entry in the field stack has any unprocessed fields.
@@ -211,7 +231,7 @@ def depth(self) -> int:
211231 return len (self ._path ) - 1
212232
213233 @property
214- def current_resource (self ):
234+ def current_resource (self ) -> Optional [ ResourceBase ] :
215235 """The current resource being traversed."""
216236 if self ._resource_stack :
217237 return self ._resource_stack [- 1 ]
0 commit comments