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 , SymmetricInt
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+ # Convert all list indices to object so negative indexes are supported.
26+ indices = map (lambda i : SymmetricInt (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,8 @@ 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+ i = zip (segments , ss_glob )
221+ for s , g in i :
218222 # Match the stars we added to the glob to the type of the
219223 # segment itself.
220224 if g is STAR :
@@ -223,10 +227,20 @@ def match(segments: Sequence[PathSegment], glob: Sequence[str]):
223227 else :
224228 g = '*'
225229
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.
229230 try :
231+ # If search path segment (s) is an int then assume currently evaluated index (g) might be a sequence
232+ # index as well. Try converting it to an int.
233+ if isinstance (s , int ) and s == int (g ):
234+ continue
235+ except :
236+ # Will reach this point if g can't be converted to an int (e.g. when g is a RegEx pattern).
237+ # In this case convert s to a str so fnmatch can work on it.
238+ s = str (s )
239+
240+ try :
241+ # Let's see if the glob matches. We will turn any kind of
242+ # exception while attempting to match into a False for the
243+ # match.
230244 if not fnmatchcase (s , g ):
231245 return False
232246 except :
@@ -391,7 +405,7 @@ def foldm(obj, f, acc):
391405 return acc
392406
393407
394- def view (obj , glob ):
408+ def view (obj : MutableMapping , glob : Glob ):
395409 """
396410 Return a view of the object where the glob matches. A view retains
397411 the same form as the obj, but is limited to only the paths that
0 commit comments