4
4
5
5
from dpath import options
6
6
from 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
8
8
9
9
10
10
def make_walkable (node ) -> Iterator [Tuple [PathSegment , Any ]]:
@@ -21,7 +21,10 @@ def make_walkable(node) -> Iterator[Tuple[PathSegment, Any]]:
21
21
return iter (node .items ())
22
22
except AttributeError :
23
23
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 )
25
28
except TypeError :
26
29
# This can happen in cases where the node isn't leaf(node) == True,
27
30
# but also isn't actually iterable. Instead of this being an error
@@ -163,7 +166,7 @@ class Star(object):
163
166
STAR = Star ()
164
167
165
168
166
- def match (segments : Sequence [ PathSegment ] , glob : Sequence [ str ] ):
169
+ def match (segments : Path , glob : Glob ):
167
170
"""
168
171
Return True if the segments match the given glob, otherwise False.
169
172
@@ -214,7 +217,8 @@ def match(segments: Sequence[PathSegment], glob: Sequence[str]):
214
217
# If we were successful in matching up the lengths, then we can
215
218
# compare them using fnmatch.
216
219
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 :
218
222
# Match the stars we added to the glob to the type of the
219
223
# segment itself.
220
224
if g is STAR :
@@ -223,10 +227,20 @@ def match(segments: Sequence[PathSegment], glob: Sequence[str]):
223
227
else :
224
228
g = '*'
225
229
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.
229
230
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.
230
244
if not fnmatchcase (s , g ):
231
245
return False
232
246
except :
@@ -391,7 +405,7 @@ def foldm(obj, f, acc):
391
405
return acc
392
406
393
407
394
- def view (obj , glob ):
408
+ def view (obj : MutableMapping , glob : Glob ):
395
409
"""
396
410
Return a view of the object where the glob matches. A view retains
397
411
the same form as the obj, but is limited to only the paths that
0 commit comments