Skip to content

Instantly share code, notes, and snippets.

@u8sand
Last active February 2, 2018 13:59
Show Gist options
  • Save u8sand/2ebbaf13b18c15158e19ce6450cfea36 to your computer and use it in GitHub Desktop.
Save u8sand/2ebbaf13b18c15158e19ce6450cfea36 to your computer and use it in GitHub Desktop.
Allows dict access via path list (e.g. path_set(d, [1,2,3], 5) == d[1][2][3]=5)
from util import *
from unittest import TestCase
class TestUtil(TestCase):
def test_path_set(self):
self.assertEquals(
path_set({}, 'a', 'b'),
{'a': 'b'},
'Basic create')
self.assertEquals(
path_set({'a': {'b': 'c'}}, ['a', 'b'], 'd'),
{'a': {'b': 'd'}},
'Replace subpath')
self.assertEquals(
path_set({'a': {'b': 'c'}}, ['b', 'a'], 'd'),
{'a': {'b': 'c'}, 'b': {'a': 'd'}},
'Create subpath')
def test_path_get(self):
self.assertEquals(
path_get({}, ['a', 'b']),
None,
'Nothing to find')
self.assertEquals(
path_get({'a': 'b'}, ['a', 'b']),
None,
'End of the line')
self.assertEquals(
path_get({'a': 'b'}, 'a'),
'b',
'Basic find')
self.assertEquals(
path_get({'a': {'b': 'c'}}, ['a', 'b']),
'c',
'Find subpath')
def test_walk_tree(self):
T = {
'a': {
'b': {
'c': 'd'
},
'e': {
'f': 'g'
},
'h': 'i'
},
'j': 'k'
}
V = set([
'a/b/c/d',
'a/e/f/g',
'a/h/i',
'j/k'
])
for k, v in walk_tree(T):
p = '/'.join(k+[v])
self.assertIn(p, V, "Path found")
V.remove(p)
self.assertEquals(V, set(), "All paths found")
def test_path_merge(self):
self.assertEquals(
path_merge({}, {'a': 'b'}),
{'a': 'b'},
'Simple create')
self.assertEquals(
path_merge({'a': 'b'}, {}),
{'a': 'b'},
'Simple create (reverse)')
self.assertEquals(
path_merge({'a': 'b'}, {'a': {'b': 'c'}}),
{'a': {'b': 'c'}},
'Overlay overwrite')
self.assertEquals(
path_merge({'a': {'b': 'c'}}, {'a': 'b'}),
{'a': 'b'},
'Overlay drop')
self.assertEquals(
path_merge({'a': {'b': {'c': 'd'}}}, {'a': {'b': {'d': 'e'}}}),
{'a': {'b': {'c': 'd', 'd': 'e'}}},
'Overlay merge')
def path_set(d, k, v):
''' Allows dict access via path list (e.g. path_set(d, [1,2,3], 5) == d[1][2][3]=5) '''
d[k[0]] = path_set(d.get(k[0], {}), k[1:], v) if len(k) > 1 else v
return d
def path_get(d, k, v=None):
''' Allows dict access via path list (e.g. path_get(d, [1,2,3]) == d[1][2][3]) '''
if isinstance(d, dict):
if len(k) > 1:
return path_get(d.get(k[0]), k[1:], v)
elif len(k) == 1:
return d.get(k[0], v)
elif len(k) == 0:
return d
return v
def walk_tree(T, K=[]):
''' Allows walking through a tree returning path list and leaf nodes--a bit like os.walk '''
for k,v in T.items():
if type(v) == dict:
for item in walk_tree(v, K+[k]):
yield item
else:
yield (K+[k], v)
def path_merge(d, *D):
''' Like dict(d, **dd for dd in D) but recusively on dicts for internal path merging '''
for DD in D:
for k, v in DD.items():
vv = d.get(k, {})
if type(vv) == dict and type(v) == dict:
d[k] = path_merge(vv, v)
else:
d[k] = v
return d
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment