44
55from dpath import options
66from dpath .exceptions import InvalidGlob , InvalidKeyName , PathNotFound
7- from dpath .types import PathSegment , Creator , Hints
7+ from dpath .types import PathSegment , Creator , Hints , Glob , Path , CyclicInt
88
99
1010def make_walkable (node ) -> Iterator [Tuple [PathSegment , Any ]]:
@@ -21,7 +21,10 @@ def make_walkable(node) -> Iterator[Tuple[PathSegment, Any]]:
2121 return iter (node .items ())
2222 except AttributeError :
2323 try :
24- return zip (range (len (node )), node )
24+ indices = range (len (node ))
25+ # Make all list indices cyclic so negative (wraparound) indexes are supported
26+ indices = map (lambda i : CyclicInt (i , len (node )), indices )
27+ return zip (indices , node )
2528 except TypeError :
2629 # This can happen in cases where the node isn't leaf(node) == True,
2730 # but also isn't actually iterable. Instead of this being an error
@@ -163,7 +166,7 @@ class Star(object):
163166STAR = Star ()
164167
165168
166- def match (segments : Sequence [ PathSegment ] , glob : Sequence [ str ] ):
169+ def match (segments : Path , glob : Glob ):
167170 """
168171 Return True if the segments match the given glob, otherwise False.
169172
@@ -214,7 +217,9 @@ def match(segments: Sequence[PathSegment], glob: Sequence[str]):
214217 # If we were successful in matching up the lengths, then we can
215218 # compare them using fnmatch.
216219 if path_len == len (ss_glob ):
217- for s , g in zip (map (int_str , segments ), map (int_str , ss_glob )):
220+ # TODO: Delete if not needed (previous code) - i = zip(map(int_str, segments), map(int_str, ss_glob))
221+ i = zip (segments , ss_glob )
222+ for s , g in i :
218223 # Match the stars we added to the glob to the type of the
219224 # segment itself.
220225 if g is STAR :
@@ -223,10 +228,15 @@ def match(segments: Sequence[PathSegment], glob: Sequence[str]):
223228 else :
224229 g = '*'
225230
226- # Let's see if the glob matches. We will turn any kind of
227- # exception while attempting to match into a False for the
228- # match.
229231 try :
232+ # If search path segment (s) is an int and the current evaluated index (g) is int-like,
233+ # then g is surely a sequence index. Convert it to int and compare.
234+ if isinstance (s , int ) and isinstance (g , str ) and (g .count ("-" ) == 0 or g .lstrip ("-" ).isdigit ()):
235+ return s == int (g )
236+
237+ # Let's see if the glob matches. We will turn any kind of
238+ # exception while attempting to match into a False for the
239+ # match.
230240 if not fnmatchcase (s , g ):
231241 return False
232242 except :
0 commit comments