diff --git a/dpath/options.py b/dpath/options.py index 41f35c4..d9b4d68 100644 --- a/dpath/options.py +++ b/dpath/options.py @@ -1 +1,4 @@ ALLOW_EMPTY_STRING_KEYS = False +REPLACE_NONE_VALUES_IN_LISTS = False +"""When creating a new subtree within a list, this option will cause dpath to treat None items as non-significant and \ +overwrite them. Default behavior will cause an exception to be thrown instead.""" diff --git a/dpath/segments.py b/dpath/segments.py index 7a48817..21aa2f6 100644 --- a/dpath/segments.py +++ b/dpath/segments.py @@ -339,6 +339,7 @@ def set( if isinstance(segment, str) and isinstance(current, Sequence) and segment.isdigit(): segment = int(segment) + create_current = False try: # Optimistically try to get the next value. This makes the # code agnostic to whether current is a list or a dict. @@ -347,10 +348,13 @@ def set( current[segment] except: if creator is not None: - creator(current, segments, i, hints) + create_current = True else: raise + if create_current or (options.REPLACE_NONE_VALUES_IN_LISTS and current[segment] is None): + creator(current, segments, i, hints) + current = current[segment] if i != length - 1 and leaf(current): raise PathNotFound(f"Path: {segments}[{i}]") diff --git a/dpath/version.py b/dpath/version.py index b777579..4260069 100644 --- a/dpath/version.py +++ b/dpath/version.py @@ -1 +1 @@ -VERSION = "2.1.2" +VERSION = "2.1.3" diff --git a/tests/test_new.py b/tests/test_new.py index 15b21c6..4b8a5a2 100644 --- a/tests/test_new.py +++ b/tests/test_new.py @@ -1,4 +1,7 @@ +from nose2.tools.such import helper + import dpath +from dpath import options def test_set_new_separator(): @@ -91,3 +94,19 @@ def mycreator(obj, pathcomp, nextpathcomp, hints): assert isinstance(d['a'], list) assert len(d['a']) == 3 assert d['a'][2] == 3 + + +def test_new_overwrite_none_in_list(): + a = {} + dpath.new(a, ['b'], []) + dpath.new(a, ['b', 3], 5) + with helper.assertRaises(dpath.exceptions.PathNotFound): + dpath.new(a, ['b', 1, "c"], 5) + + options.REPLACE_NONE_VALUES_IN_LISTS = True + a = {} + dpath.new(a, ['b'], []) + dpath.new(a, ['b', 3], 5) + dpath.new(a, ['b', 1, "c"], 5) + + assert a["b"][1]["c"] == 5