Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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