Nested Data

Because sequences of nested data really come in all sorts of shapes and sizes this library offers verbs to help you reshape the data into different formats. This document will demonstrate how these verbs work.

Explode

Sometimes you'll have data that is nested as a list of values. If you'd like to expand such a list of values you can use .explode().

from clumper import Clumper

data = [{'a': 1, 'items': [1, 2]}]

clumper = Clumper(data).explode("items")
assert clumper.equals([{'a': 1, 'items': 1}, {'a': 1, 'items': 2}])

new_data = Clumper(data).explode(item="items").collect()
assert clumper.equals([{'a': 1, 'item': 1}, {'a': 1, 'item': 2}])

Note how the syntax allows you to either explode the values, assigning them to the old keyname or to directly rename this field. You can also pass multiple keys in a single command.

from clumper import Clumper

data = [{'a': 1, 'items': [1, 2], 'values':[3, 4]}]

clumper = Clumper(data).explode("items", "values")
expected = [
    {'a': 1, 'items': 1, 'values': 3},
    {'a': 1, 'items': 1, 'values': 4},
    {'a': 1, 'items': 2, 'values': 3},
    {'a': 1, 'items': 2, 'values': 4}
]
assert clumper.equals(expected)

new_data = Clumper(data).explode(item="items", val="values").collect()
expected = [
    {'a': 1, 'item': 1, 'val': 3},
    {'a': 1, 'item': 1, 'val': 4},
    {'a': 1, 'item': 2, 'val': 3},
    {'a': 1, 'item': 2, 'val': 4}
]
assert clumper.equals(expected)

Unpack

The unpack verb is very similar to explode but here we expect a list of dictionaries as opposed to a list of values.

from clumper import Clumper

list_dicts = {
    'a': 1,
    'rows': [{'b': 2, 'c': 3}, {'b': 3}, {'b': 4}]
}

result = Clumper(list_dicts).unpack('rows').collect()

expected = [
    {'a': 1, 'b': 2, 'c': 3},
    {'a': 1, 'b': 3},
    {'a': 1, 'b': 4}
]

assert result == expected

Single Dictionaries

Sometimes you're dealing with json data that isn't a list of dictionaries. You should be aware that you may want to read in the data differently. You can keep the data as a dictionary or automatically wrap it as a list by tweaking the listify parameter. This is available on every .read_<format>-method.

Listify = True

from clumper import Clumper

example1 = Clumper.read_yaml("tests/data/demo-nested.yml")
expected1 = [
    {
        'nested1': [
            {'item': 1, 'value': 'a'},
            {'item': 2, 'value': 'b'},
            {'item': 3, 'value': 'c'}
        ],
        'nested2': [
            {'item': 1, 'value': 'a'},
            {'item': 2, 'value': 'b'},
            {'item': 3, 'value': 'c'}
        ]
    }
]
assert example1.equals(expected1)

Listify = False

from clumper import Clumper
example2 = Clumper.read_yaml("tests/data/demo-nested.yml", listify=False)
expected2 = {
    'nested1': [
        {'item': 1, 'value': 'a'},
        {'item': 2, 'value': 'b'},
        {'item': 3, 'value': 'c'}
    ],
    'nested2': [
        {'item': 1, 'value': 'a'},
        {'item': 2, 'value': 'b'},
        {'item': 3, 'value': 'c'}
    ]
}
assert example2.equals(expected2)

Flatten Keys

In the "list-like dictionary" scenarios you might want to use .flatten_keys. This method flattens the keys in the data.

from clumper import Clumper

data = {
  'feature_1': {'propery_1': 1, 'property_2': 2},
  'feature_2': {'propery_1': 3, 'property_2': 4},
  'feature_3': {'propery_1': 5, 'property_2': 6},
}

expected = [
    {'propery_1': 1, 'property_2': 2, 'key': 'feature_1'},
    {'propery_1': 3, 'property_2': 4, 'key': 'feature_2'},
    {'propery_1': 5, 'property_2': 6, 'key': 'feature_3'}
]

assert Clumper(data, listify=False).flatten_keys().collect() == expected

Show

Getting the verbs right can be trick. So we've also added a show verb which can be useful while debugging. It requires rich to be manually installed beforehand if you want to see the pretty colors in the output.

from clumper import Clumper

data = [{"n": 123, "data": [1, 2, 3], "maintainer": "Vincent"}]
Clumper(data).show("Before", n=1).explode("data").show("After", n=3)