File: tree.py

package info (click to toggle)
python-pytray 0.3.5-4
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 192 kB
  • sloc: python: 510; sh: 30; makefile: 3
file content (71 lines) | stat: -rw-r--r-- 2,607 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# -*- coding: utf-8 -*-
"""A tree in this context is considered a nested container containing either lists or
dictionaries and with anything else being considered a leaf.  Paths to particular points
in the data structure are represented as sequences containing the index at each level"""
from functools import reduce
import operator


def get_by_path(root, items):
    """Access a nested object in root by item sequence.  Taken from:
    https://stackoverflow.com/questions/14692690/access-nested-dictionary-items-via-a-list-of-keys"""
    if not items:
        # Support either empty items or None items meaning give back root
        return root
    return reduce(operator.getitem, items, root)


def set_by_path(root, items, value):
    """Set a value in a nested object in root by item sequence.  Taken from:
    https://stackoverflow.com/questions/14692690/access-nested-dictionary-items-via-a-list-of-keys"""
    get_by_path(root, items[:-1])[items[-1]] = value


def path_to_string(path: tuple) -> str:
    return ".".join((str(key) for key in path))


def transform(visitor, root, path: tuple = (), **kwargs):
    """Given a list or a dict call create a new container of that type calling
    `visitor` for each entry to get the transformed value.  kwargs will be passed
    to the visitor.
    """

    if isinstance(root, dict):
        return {
            key: visitor(value, path=path + (key,), **kwargs)
            for key, value in root.items()
        }
    if isinstance(root, list):
        return [
            visitor(value, path=path + (idx,), **kwargs)
            for idx, value in enumerate(root)
        ]

    return root


def flatten(root, filter=None) -> dict:  # pylint: disable=redefined-builtin
    """Given a tree flatten it into a dictionary contaning the path as key and the corresponding
    leaves as values"""

    def should_flatten(value):
        return (isinstance(value, (dict, list)) and bool(value)) and (
            filter is None or filter(value)
        )

    def do_flattening(entry, path=()):
        if should_flatten(entry):
            # Descend further
            if isinstance(entry, dict):
                for key, value in entry.items():
                    yield from do_flattening(value, path + (key,))
            elif isinstance(entry, list):
                for idx, value in enumerate(entry):
                    yield from do_flattening(value, path + (idx,))
            else:
                raise TypeError("Cannot flatten type '{}'".format(type(entry)))
        else:
            yield path, entry

    return dict(do_flattening(root))