Skip to content

Commit ea64635

Browse files
authored
Merge pull request #169 from dpath-maintainers/bugfix/int-ambiguity
Bugfix/int ambiguity
2 parents 702b5dd + 38007df commit ea64635

File tree

5 files changed

+30
-18
lines changed

5 files changed

+30
-18
lines changed

dpath/__init__.py

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
_DEFAULT_SENTINEL = object()
3131

3232

33-
def _split_path(path: Path, separator: Optional[str]) -> Union[List[PathSegment], PathSegment]:
33+
def _split_path(path: Path, separator: Optional[str] = "/") -> Union[List[PathSegment], PathSegment]:
3434
"""
3535
Given a path and separator, return a tuple of segments. If path is
3636
already a non-leaf thing, return it.
@@ -45,16 +45,6 @@ def _split_path(path: Path, separator: Optional[str]) -> Union[List[PathSegment]
4545
else:
4646
split_segments = path.lstrip(separator).split(separator)
4747

48-
if options.CONVERT_INT_LIKE_SEGMENTS:
49-
# Attempt to convert integer segments into actual integers.
50-
final = []
51-
for segment in split_segments:
52-
try:
53-
final.append(int(segment))
54-
except ValueError:
55-
final.append(segment)
56-
split_segments = final
57-
5848
return split_segments
5949

6050

dpath/options.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
11
ALLOW_EMPTY_STRING_KEYS = False
2-
CONVERT_INT_LIKE_SEGMENTS = True

dpath/segments.py

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ def set(
309309
) -> MutableMapping:
310310
"""
311311
Set the value in obj at the place indicated by segments. If creator is not
312-
None (default __default_creator__), then call the creator function to
312+
None (default _default_creator), then call the creator function to
313313
create any missing path components.
314314
315315
set(obj, segments, value) -> obj
@@ -320,13 +320,18 @@ def set(
320320
# For everything except the last value, walk down the path and
321321
# create if creator is set.
322322
for (i, segment) in enumerate(segments[:-1]):
323+
324+
# If segment is non-int but supposed to be a sequence index
325+
if isinstance(segment, str) and isinstance(current, Sequence) and segment.isdigit():
326+
segment = int(segment)
327+
323328
try:
324329
# Optimistically try to get the next value. This makes the
325330
# code agnostic to whether current is a list or a dict.
326331
# Unfortunately, for our use, 'x in thing' for lists checks
327332
# values, not keys whereas dicts check keys.
328333
current[segment]
329-
except (KeyError, IndexError):
334+
except:
330335
if creator is not None:
331336
creator(current, segments, i, hints)
332337
else:
@@ -336,10 +341,16 @@ def set(
336341
if i != length - 1 and leaf(current):
337342
raise PathNotFound(f"Path: {segments}[{i}]")
338343

339-
if isinstance(segments[-1], int):
340-
extend(current, segments[-1])
344+
last_segment = segments[-1]
345+
346+
# Resolve ambiguity of last segment
347+
if isinstance(last_segment, str) and isinstance(current, Sequence) and last_segment.isdigit():
348+
last_segment = int(last_segment)
341349

342-
current[segments[-1]] = value
350+
if isinstance(last_segment, int):
351+
extend(current, last_segment)
352+
353+
current[last_segment] = value
343354

344355
return obj
345356

@@ -388,9 +399,11 @@ def view(obj, glob):
388399
389400
view(obj, glob) -> obj'
390401
"""
402+
391403
def f(obj, pair, result):
392404
(segments, value) = pair
393405
if match(segments, glob):
394406
if not has(result, segments):
395407
set(result, segments, deepcopy(value), hints=types(obj, segments))
408+
396409
return fold(obj, f, type(obj)())

dpath/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
VERSION = "2.1.0"
1+
VERSION = "2.1.1"

tests/test_new.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,16 @@ def test_set_new_list():
4242
assert dict['a'][0] is None
4343

4444

45+
def test_set_list_with_dict_int_ambiguity():
46+
d = {"list": [{"root": {"1": {"k": None}}}]}
47+
48+
dpath.new(d, "list/0/root/1/k", "new")
49+
50+
expected = {"list": [{"root": {"1": {"k": "new"}}}]}
51+
52+
assert d == expected
53+
54+
4555
def test_set_new_list_path_with_separator():
4656
# This test kills many birds with one stone, forgive me
4757
dict = {

0 commit comments

Comments
 (0)