-
Notifications
You must be signed in to change notification settings - Fork 349
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
remap enter to skip some items #87
Comments
remap is just letting you know that with that enter, absolutely no remapping would occur. If the very first enter returns |
Maybe the error message could be improved, but I don't know how to formulate it better :-/ def enter(path, key, value):
# I'd like to skip `baz's`
if 'baz' in value and isinstance(value, dict):
value.pop('baz')
return default_enter(path, key, value)
print(remap({'foo': 'bar', 'baz': 'qux', 'data': ['foo', 'bar', 'baz']}, enter=enter))
>>> {'foo': 'bar', 'data': ['foo', 'bar', 'baz']} Originally my problem is next: I have a nested dictionaries, which represents hierarchical configuration object. All children should inherit parent properties, they can append to them or override them. And what I need is to transpose this hierarchical structure, so I can ask each node about its properties taking into account parent properties. import copy
d = {
'name': 'ROOT',
'properties': ['foo'],
'includes': [
{
'name': 'nested-1',
'properties-override': ['bar', 'baz'],
'includes': [
{'id': '1'},
{'id': '2', 'properties': ['quz']},
{'id': '3'},
]
}
]
}
def traverse(data, parents=None):
result = list()
if parents is None:
parents = list()
if 'id' in data:
assert 'includes' not in data
data['parents'] = copy.deepcopy(parents)
return [data]
else:
includes = data.pop('includes', list())
parents.append(data)
if not isinstance(includes, list):
includes = [includes]
for inc in includes:
child = traverse(inc, parents)
result.extend(child)
parents.pop()
return result
if __name__ == '__main__':
for item in traverse(d):
print(item)
>>> {'id': '1', 'parents': [{'name': 'ROOT', 'properties': ['foo']}, {'properties-override': ['bar', 'baz'], 'name': 'nested-1'}]}
>>> {'id': '2', 'properties': ['quz'], 'parents': [{'name': 'ROOT', 'properties': ['foo']}, {'properties-override': ['bar', 'baz'], 'name': 'nested-1'}]}
>>> {'id': '3', 'parents': [{'name': 'ROOT', 'properties': ['foo']}, {'properties-override': ['bar', 'baz'], 'name': 'nested-1'}]} Can the same problem be solved with |
Okay, looks like I implemented the same traverse method with remap functionality, but I don't know whether it's optimal or not: import copy
from boltons.iterutils import remap, default_enter, default_exit
d = {
'name': 'ROOT',
'properties': ['foo'],
'includes': [
{
'name': 'nested-1',
'properties-override': ['bar', 'baz'],
'includes': [
{'id': '1'},
{'id': '2', 'properties': ['quz']},
{'id': '3'},
]
}
]
}
def traverse(data=None):
if not data:
data = d
result = list()
parents = list()
def enter(path, key, value):
if 'includes' in value:
includes = value.pop('includes')
parents.append(value)
value = includes
res = default_enter(path, key, value)
return res
def visit(path, key, value):
if 'id' in value and isinstance(value, dict):
item = copy.deepcopy(value)
item['parents'] = copy.deepcopy(parents)
result.append(item)
return key, value
def exit(path, key, old_parent, new_parent, new_items):
if old_parent == parents[-1]:
parents.pop()
res = default_exit(path, key, old_parent, new_parent, new_items)
return res
remap(data, visit=visit, enter=enter, exit=exit)
return result
if __name__ == '__main__':
for item in traverse(d):
print(item)
>>> {'id': '1', 'parents': [{'name': 'ROOT', 'properties': ['foo']}, {'properties-override': ['bar', 'baz'], 'name': 'nested-1'}]}
>>> {'id': '2', 'properties': ['quz'], 'parents': [{'name': 'ROOT', 'properties': ['foo']}, {'properties-override': ['bar', 'baz'], 'name': 'nested-1'}]}
>>> {'id': '3', 'parents': [{'name': 'ROOT', 'properties': ['foo']}, {'properties-override': ['bar', 'baz'], 'name': 'nested-1'}]} |
Ah, it's still not perfect, but won't bother you with opened ticket. |
During iteration through data I would like to skip some items.
As described in docs, it should be possible to skip visiting some elements if return
False
as a second value from return. But even with such a trivial example I've got an error:Am I doing something wrong or it's a bug?
The text was updated successfully, but these errors were encountered: