Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

adding option to create nested lists on the fly #93

Closed
Closed
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
32 changes: 32 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,38 @@ object with None entries in order to make it big enough:

Handy!

Even more handy, you can also tell dpath.util.new to interpret integers as list indices so that new lists are automatically created. This is very convenient to create nested lists.

.. code-block:: pycon

>>> x={}
>>> dpath.util.new(x, 'a/2/3', 5, integer_as_list_index = False)
>>> print json.dumps(x, indent=4, sort_keys=True)
{
"a": {
"2": {
"3": 5
}
}
}
>>> x={}
>>> dpath.util.new(x, 'a/2/3', 5, integer_as_list_index = True)
>>> print json.dumps(x, indent=4, sort_keys=True)
{
"a": [
null,
null,
[
null,
null,
null,
5
]
]
}

you can setup the default value for integer_as_list_index to True using dpath.options.INTEGERS_AS_LIST_INDICES=True

Example: Merging
================

Expand Down
1 change: 1 addition & 0 deletions dpath/options.py
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
ALLOW_EMPTY_STRING_KEYS = False
INTEGERS_AS_LIST_INDICES = False
32 changes: 22 additions & 10 deletions dpath/path.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,41 @@
import traceback
from collections import MutableSequence, MutableMapping

def path_types(obj, path):
def path_types(obj, path, integer_as_list_index=None):
"""
Given a list of path name elements, return anew list of [name, type] path components, given the reference object.
"""
if integer_as_list_index is None:
integer_as_list_index = dpath.options.INTEGERS_AS_LIST_INDICES

result = []
#for elem in path[:-1]:
cur = obj
for elem in path[:-1]:
for nelem,elem in enumerate(path[:-1]):
if ((issubclass(cur.__class__, MutableMapping) and elem in cur)):
result.append([elem, cur[elem].__class__])
cur = cur[elem]
elif (issubclass(cur.__class__, MutableSequence) and int(elem) < len(cur)):
elif (issubclass(cur.__class__, MutableSequence) and int(elem) < len(cur)) and not(cur[elem] is None):
elem = int(elem)
result.append([elem, cur[elem].__class__])
cur = cur[elem]
else:
result.append([elem, dict])
try:
try:
result.append([path[-1], cur[path[-1]].__class__])
except TypeError:
result.append([path[-1], cur[int(path[-1])].__class__])
except (KeyError, IndexError):
if integer_as_list_index and (isinstance(path[nelem+1],int) or path[nelem+1].isdigit()) :
result.append([elem, list])
cur=None
else:
result.append([elem, dict])
cur=None
if cur is None:
result.append([path[-1], path[-1].__class__])
else:
try:
try:
result.append([path[-1], cur[path[-1]].__class__])
except TypeError:
result.append([path[-1], cur[int(path[-1])].__class__])
except (KeyError, IndexError):
result.append([path[-1], path[-1].__class__])
return result

def paths_only(path):
Expand Down Expand Up @@ -173,6 +184,7 @@ def _create_missing_list(obj, elem):
idx = int(str(elem[0]))
while (len(obj)-1) < idx:
obj.append(None)
obj[idx]=elem[1]()

def _accessor_dict(obj, elem):
return obj[elem[0]]
Expand Down
4 changes: 2 additions & 2 deletions dpath/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def __safe_path__(path, separator):
validated.append(strkey)
return path

def new(obj, path, value, separator="/"):
def new(obj, path, value, separator="/",integer_as_list_index=None):
"""
Set the element at the terminus of path to value, and create
it if it does not exist (as opposed to 'set' that can only
Expand All @@ -43,7 +43,7 @@ def new(obj, path, value, separator="/"):
keys
"""
pathlist = __safe_path__(path, separator)
pathobj = dpath.path.path_types(obj, pathlist)
pathobj = dpath.path.path_types(obj, pathlist,integer_as_list_index)
return dpath.path.set(obj, pathobj, value, create_missing=True)

def delete(obj, glob, separator="/", afilter=None):
Expand Down
2 changes: 1 addition & 1 deletion dpath/version.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import os

VERSION="1.4.2"
VERSION="1.4.3"
12 changes: 12 additions & 0 deletions tests/test_util_new.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,18 @@ def test_set_new_list():
dpath.util.new(dict, ['a', '1'], 1)
assert(dict['a'][1] == 1)
assert(dict['a'][0] == None)

def test_set_new_list_with_integer_as_list_index():
dict = {}
dpath.util.new(dict, 'a/2/3', 5,integer_as_list_index = True)
assert(len(dict['a']) == 3)
assert(dict['a'][0] == None)
assert(dict['a'][1] == None)
assert(len(dict['a'][2]) == 4)
assert(dict['a'][2][0] == None)
assert(dict['a'][2][1] == None)
assert(dict['a'][2][2] == None)
assert(dict['a'][2][3] == 5)

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