Basic Usage Examples

After a short example about the basic behavior of AnAugmentedTreeItem (for more details) examples will show how to

Basic behavior of AnAugmentedTreeItem

An ‘augmented’ dictionary or sequence will keep their native behavior, due to the goal of augmentedtree to not interfere with other python modules/packages working with native python mappings and sequences. AnAugmentedTreeItem enhances the nested data.

Accessing AnAugmentedTreeItem by index will return the nested data on basis of its augmented path.

[105]:
from augmentedtree import AugmentedTree
nested_data = {"a": 1, "b": [1, 2, 3], "c": {"d": 3}}
atree = AugmentedTree(nested_data)
print(atree["a"], type(atree["a"]))
print(atree["b"], type(atree["b"]))
print(atree["c"], type(atree["c"]))
1 <class 'int'>
[1, 2, 3] <class 'list'>
{'d': 3} <class 'dict'>

Mappings and sequences can be used like before.

[106]:
print(atree["a"])
print(atree["b"][1])
print(atree["c"]["d"])

1
2
3

The nested exemplary data

Within the following examples this nested data will be used.

[107]:
nested_data = {
    "A1": {
        "B1": {
            "C1": {"x11": 11, "x21": 21, "x31": 31},
            "C2": {"x12": 12, "x22": 22},
            "C3": {"x13": 13},
        },
        "B2": {
            "C1": {"x11": 110, "x21": 210, "x31": 310},
            "C2": {"x12": 120, "x22": 220},
        },
        "B3": {
            "C1": {"x11": 1100, "x21": 2100, "x31": 3100}
        }
    },
    "A2": {
        "B1": {
            "C1": {"x11": 211, "x21": 221, "x31": 231},
            "C2": {"x12": 212, "x22": 222},
            "C3": {"x13": 213},
        }
    }
}

Examples on how to

Access values using select

Selecting items by using a single key.

[108]:
atree = AugmentedTree(nested_data)
all_x12_items = atree.select("x12")
all_x12_items.print()

#0 12
#1 120
#2 212

Selecting items by using multiple keys.

Keys needs to be in order of their occurrence within the desired items augmented path.

[109]:
atree = AugmentedTree(nested_data)
all_x12_items_at_A2 = atree.select("A2", "x12")
all_x12_items_at_A2.print()
#0 212
[110]:
not_working = atree.select("x12", "A2")
print("Returning nothing", not_working[:])
Returning nothing []

Selecting using UNIX wildcards

A selection using the well known and beloved UNIX filename search pattern is supported.

Using the questionmark

[111]:
atree = AugmentedTree(nested_data)
allitems_having_a_leading_1 = atree.select("x1?")
allitems_having_a_leading_1.treeitems.print()
#0 /A1/B1/C1/x11
  11
#1 /A1/B1/C2/x12
  12
#2 /A1/B1/C3/x13
  13
#3 /A1/B2/C1/x11
  110
#4 /A1/B2/C2/x12
  120
#5 /A1/B3/C1/x11
  1100
#6 /A2/B1/C1/x11
  211
#7 /A2/B1/C2/x12
  212
#8 /A2/B1/C3/x13
  213

Using a range of numbers

Using a range of numbers

[112]:
allitems_having_only_1_and_3 = atree.select("x[13][13]")
allitems_having_only_1_and_3.treeitems.print()
#0 /A1/B1/C1/x11
  11
#1 /A1/B1/C1/x31
  31
#2 /A1/B1/C3/x13
  13
#3 /A1/B2/C1/x11
  110
#4 /A1/B2/C1/x31
  310
#5 /A1/B3/C1/x11
  1100
#6 /A1/B3/C1/x31
  3100
#7 /A2/B1/C1/x11
  211
#8 /A2/B1/C1/x31
  231
#9 /A2/B1/C3/x13
  213

Getting all unknown items of a specific item

new in release 0.2a0

Using a path delimiter with a trailing single asterisk wildcard “/*” selects only items at that level, instead of all sub items (default).

[113]:
all_next_level_subitems_of_b2 = atree.select("B2/*")
all_next_level_subitems_of_b2.treeitems.print()
#0 /A1/B2/C1
  C1:
    x11: 110
    x21: 210
    x31: 310

#1 /A1/B2/C2
  C2:
    x12: 120
    x22: 220

If the star * wildcard is used as a stand-alone path part, it will return all sub tree item from its root(s).

[114]:
all_subitems_of_b2 = atree.select("B2", "*")
all_subitems_of_b2.treeitems.print()
#0 /A1/B2/C1
  C1:
    x11: 110
    x21: 210
    x31: 310

#1 /A1/B2/C1/x11
  110
#2 /A1/B2/C1/x21
  210
#3 /A1/B2/C1/x31
  310
#4 /A1/B2/C2
  C2:
    x12: 120
    x22: 220

#5 /A1/B2/C2/x12
  120
#6 /A1/B2/C2/x22
  220

Selecting using regular expression

With regular expression a powerful tool for selection is available.

[115]:
from augmentedtree import RegularExpressionParts as REPs
allitems_having_only_1 = atree.select(REPs("x[1]{2}"))
allitems_having_only_1.treeitems.print()

#0 /A1/B1/C1/x11
  11
#1 /A1/B2/C1/x11
  110
#2 /A1/B3/C1/x11
  1100
#3 /A2/B1/C1/x11
  211

Select with Or condition

Wrapping multiple of path parts with a tuple, a list, an UnixFilePatternPart or a RegularExpressionPart makes these parts behave like an or condition in between them.

select("A", ("B", "C"), "D")
            is equal to
        A and (B or C) and D
[116]:
from augmentedtree import RegularExpressionParts as REPs
all_x11_items_of_B1_or_Y1 = atree.select(REPs("B1", "Y1"), "x11")
all_x11_items_of_B1_or_Y1.treeitems.print()

#0 /A1/B1/C1/x11
  11
#1 /A2/B1/C1/x11
  211

Working with selections

Accessing single items

[117]:
atree = AugmentedTree(nested_data)
all_x12_items = atree.select("x12")
second_found_value = all_x12_items[1]
print(second_found_value)
120
[118]:
second_item = all_x12_items.treeitems[1]
print(second_item)
ValueTreeItem(x12: 120)

Accessing slices

Selections can be accessed using slices. For a better readability of scripts AugmentedTree.ALL_ITEMS can be used.

[119]:
from augmentedtree import ALL_ITEMS

atree = AugmentedTree(nested_data)
all_x12_items = atree.select("x12")
all_values = all_x12_items[ALL_ITEMS]
print(all_values)

[12, 120, 212]
[120]:
all_except_last = all_x12_items[:-1]
print(all_except_last)
[12, 120]

Setting multiple values at different locations at once

[121]:
from copy import deepcopy
temp_nested_data = deepcopy(nested_data)
atree = AugmentedTree(temp_nested_data)

# Select items
all_x11_items = atree.select("x11")

# Set all items to a new values
all_x11_items[ALL_ITEMS] = "My key is x11."

atree.print()
{..}
  A1:
    B1:
      C1:
        x11: My key is x11.
        x21: 21
        x31: 31
      C2:
        x12: 12
        x22: 22
      C3:
        x13: 13
    B2:
      C1:
        x11: My key is x11.
        x21: 210
        x31: 310
      C2:
        x12: 120
        x22: 220
    B3:
      C1:
        x11: My key is x11.
        x21: 2100
        x31: 3100
  A2:
    B1:
      C1:
        x11: My key is x11.
        x21: 221
        x31: 231
      C2:
        x12: 212
        x22: 222
      C3:
        x13: 213

[122]:
all_x11_items[1:3] = "A value set by using slicing."

atree.print()
{..}
  A1:
    B1:
      C1:
        x11: My key is x11.
        x21: 21
        x31: 31
      C2:
        x12: 12
        x22: 22
      C3:
        x13: 13
    B2:
      C1:
        x11: A value set by using slicing.
        x21: 210
        x31: 310
      C2:
        x12: 120
        x22: 220
    B3:
      C1:
        x11: A value set by using slicing.
        x21: 2100
        x31: 3100
  A2:
    B1:
      C1:
        x11: My key is x11.
        x21: 221
        x31: 231
      C2:
        x12: 212
        x22: 222
      C3:
        x13: 213

Viewing treeitems

AnAugmentedTreeItem will give you a different output in whether you use print(treeitem) or treeitem.print().

The standard output resembles the nested data wrapped by AnAugmentedTreeItem. An exception is a ValueTreeItem in which its key (primekey) is also print out for more convenience.

[123]:
root_level = {
    "ridiculous-level": {
        "ludicrous-level": "They've gone into plaid."
    }
}

spacetree = AugmentedTree(root_level)
ridiculous_item = spacetree.children["ridiculous-level"]
ludicrous_item = ridiculous_item.children["ludicrous-level"]
print(spacetree)
print(ridiculous_item)
print(ludicrous_item)
AugmentedTree({'ridiculous-level': {'ludicrous-level': "They've gone into plaid."}})
MappingTreeItem({'ludicrous-level': "They've gone into plaid."})
ValueTreeItem(ludicrous-level: They've gone into plaid.)

Using AnAgumentedTreeItem’s print method gives a different output.

[124]:
print("# spacetree")
spacetree.print()
print("# ridiculous_treeitem")
ridiculous_item.print()
print("# ludicrous_treeitem")
ludicrous_item.print()
# spacetree
{..}
  ridiculous-level:
    ludicrous-level: They've gone into plaid.

# ridiculous_treeitem
ridiculous-level:
  ludicrous-level: They've gone into plaid.

# ludicrous_treeitem
They've gone into plaid.

Sorting tree item selections

new in release 0.2a0

The main purpose of the sort-method is to sort selections. If the nested data should be sorted, its more efficient to use specific packages and re-augment the sorted result. In many cases a sorted result of a selection is desired.

Tree items can be sorted using the sort method of AugmentedTreeItem or AugmentedItemSelection. By default the tree items are sorted in regard of their augmented_path.

The current implementation does not sort the nested data itself. It sorts the tree items. It can be compared to a reorganized view, while the original data keeps its order.

Exemplary behavior

This example shows a simple nested structure with 6 leafs.

[125]:
from augmentedtree import AugmentedTree

data = {
    "b": {
        "a-1": 1,
        "b-1": 2
    },
    "a": {
        "a-2": 3,
        "a-13": 4,
        "b-2": 5,
        "b-13": 6,
    }
}

a_tree = AugmentedTree(data)
a_tree.print()
{..}
  b:
    a-1: 1
    b-1: 2
  a:
    a-2: 3
    a-13: 4
    b-2: 5
    b-13: 6

The tree items inherits the order of the given structure.

[126]:
a_tree.treeitems.print()
#0 /b
  b:
    a-1: 1
    b-1: 2

#1 /b/a-1
  1
#2 /b/b-1
  2
#3 /a
  a:
    a-2: 3
    a-13: 4
    b-2: 5
    b-13: 6

#4 /a/a-2
  3
#5 /a/a-13
  4
#6 /a/b-2
  5
#7 /a/b-13
  6

Sorting the tree affects the global order of the tree items, but not the local order or the nested data itself.

[127]:
sorting_tree = a_tree.sort()
sorting_tree.print()
{..}
  b:
    a-1: 1
    b-1: 2
  a:
    a-2: 3
    a-13: 4
    b-2: 5
    b-13: 6

[128]:
sorting_tree.treeitems.print()
#0 /a
  a:
    a-2: 3
    a-13: 4
    b-2: 5
    b-13: 6

#1 /a/a-13
  4
#2 /a/a-2
  3
#3 /a/b-13
  6
#4 /a/b-2
  5
#5 /b
  b:
    a-1: 1
    b-1: 2

#6 /b/a-1
  1
#7 /b/b-1
  2

Basic usage of sorting

The main purpose is to sort selections. The default sorting order is based on the augmented path.

[129]:
all_bees = a_tree.select("b-*").sort()
all_bees.treeitems.print()

#0 /a/b-13
  6
#1 /a/b-2
  5
#2 /b/b-1
  2

A different sorting order might be desired, which can be achieved using the Callable[[PathMapItem], int] interface.

[130]:
from augmentedtree.treeitemselection import PathMapItem

def sort_by_trailing_item_number(path_map_item: PathMapItem) -> int:
    number_characters = path_map_item.primekey.split("-")[1]
    try:
        return int(number_characters)
    except TypeError:
        return 0

all_bees = a_tree.select("b-*").sort(sorting_method=sort_by_trailing_item_number)
all_bees.treeitems.print()
#0 /b/b-1
  2
#1 /a/b-2
  5
#2 /a/b-13
  6