Skip to content

Commit

Permalink
Merge pull request #169 from dpath-maintainers/bugfix/int-ambiguity
Browse files Browse the repository at this point in the history
Bugfix/int ambiguity
  • Loading branch information
moomoohk authored Nov 30, 2022
2 parents 702b5dd + 38007df commit ea64635
Show file tree
Hide file tree
Showing 5 changed files with 30 additions and 18 deletions.
12 changes: 1 addition & 11 deletions dpath/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
_DEFAULT_SENTINEL = object()


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

if options.CONVERT_INT_LIKE_SEGMENTS:
# Attempt to convert integer segments into actual integers.
final = []
for segment in split_segments:
try:
final.append(int(segment))
except ValueError:
final.append(segment)
split_segments = final

return split_segments


Expand Down
1 change: 0 additions & 1 deletion dpath/options.py
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
ALLOW_EMPTY_STRING_KEYS = False
CONVERT_INT_LIKE_SEGMENTS = True
23 changes: 18 additions & 5 deletions dpath/segments.py
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ def set(
) -> MutableMapping:
"""
Set the value in obj at the place indicated by segments. If creator is not
None (default __default_creator__), then call the creator function to
None (default _default_creator), then call the creator function to
create any missing path components.
set(obj, segments, value) -> obj
Expand All @@ -320,13 +320,18 @@ def set(
# For everything except the last value, walk down the path and
# create if creator is set.
for (i, segment) in enumerate(segments[:-1]):

# If segment is non-int but supposed to be a sequence index
if isinstance(segment, str) and isinstance(current, Sequence) and segment.isdigit():
segment = int(segment)

try:
# Optimistically try to get the next value. This makes the
# code agnostic to whether current is a list or a dict.
# Unfortunately, for our use, 'x in thing' for lists checks
# values, not keys whereas dicts check keys.
current[segment]
except (KeyError, IndexError):
except:
if creator is not None:
creator(current, segments, i, hints)
else:
Expand All @@ -336,10 +341,16 @@ def set(
if i != length - 1 and leaf(current):
raise PathNotFound(f"Path: {segments}[{i}]")

if isinstance(segments[-1], int):
extend(current, segments[-1])
last_segment = segments[-1]

# Resolve ambiguity of last segment
if isinstance(last_segment, str) and isinstance(current, Sequence) and last_segment.isdigit():
last_segment = int(last_segment)

current[segments[-1]] = value
if isinstance(last_segment, int):
extend(current, last_segment)

current[last_segment] = value

return obj

Expand Down Expand Up @@ -388,9 +399,11 @@ def view(obj, glob):
view(obj, glob) -> obj'
"""

def f(obj, pair, result):
(segments, value) = pair
if match(segments, glob):
if not has(result, segments):
set(result, segments, deepcopy(value), hints=types(obj, segments))

return fold(obj, f, type(obj)())
2 changes: 1 addition & 1 deletion dpath/version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
VERSION = "2.1.0"
VERSION = "2.1.1"
10 changes: 10 additions & 0 deletions tests/test_new.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,16 @@ def test_set_new_list():
assert dict['a'][0] is None


def test_set_list_with_dict_int_ambiguity():
d = {"list": [{"root": {"1": {"k": None}}}]}

dpath.new(d, "list/0/root/1/k", "new")

expected = {"list": [{"root": {"1": {"k": "new"}}}]}

assert d == expected


def test_set_new_list_path_with_separator():
# This test kills many birds with one stone, forgive me
dict = {
Expand Down

0 comments on commit ea64635

Please sign in to comment.