Converters
Functions for flattening nested YAML/dict structures into tabular format.
- mdstools.converters.flatten.flatten(d, prefix='', parent_key=None)
Flatten a nested YAML structure into a tabular format with numbered rows.
- Parameters:
d – The data structure to flatten (dict or list)
prefix – The current numbering prefix (default: “”)
parent_key – The parent key name (default: None)
- Returns:
A list of rows, each containing [number, key, value]
EXAMPLES:
Simple key-value pairs:
>>> data = { ... 'experiment': 'abc'} >>> flatten(data) [['1', 'experiment', 'abc']] >>> data = { ... 'experiment': 'abc', ... 'details': 'foo'} >>> flatten(data) [['1', 'experiment', 'abc'], ['2', 'details', 'foo']]
Nested dictionaries:
>>> data = { ... 'experiment': {'value': 42, 'units': 'mV'}} >>> flatten(data) [['1', 'experiment', '<nested>'], ['1.1', 'value', 42], ['1.2', 'units', 'mV']]
Lists of dictionaries:
>>> data = { ... 'experiment': [{'A': 1, 'B': 2}, {'A': 3, 'B': 4}]} >>> flatten(data) [['1', 'experiment', '<nested>'], ['1.i1.1', 'A', 1], ['1.i1.2', 'B', 2], ['1.i2.1', 'A', 3], ['1.i2.2', 'B', 4]]
Primitive lists:
>>> data = { ... 'measurements': ['A', 'B', 'C']} >>> flatten(data) [['1', 'measurements', '<nested>'], ['1.i1', '', 'A'], ['1.i2', '', 'B'], ['1.i3', '', 'C']]
Mixed nested structures:
>>> data = { ... 'experiment': [{'A': {'value': 1, 'units': 'mV'}, 'B': 2}, {'A': 3, 'B': 4}]} >>> flatten(data) [['1', 'experiment', '<nested>'], ['1.i1.1', 'A', '<nested>'], ['1.i1.1.1', 'value', 1], ['1.i1.1.2', 'units', 'mV'], ['1.i1.2', 'B', 2], ['1.i2.1', 'A', 3], ['1.i2.2', 'B', 4]]
- mdstools.converters.flatten.is_primitive_list(lst)
Check if a list contains only primitive values (no dicts or lists).
Returns True if every element is a simple scalar (str, int, float, bool, None), and False if any element is a dict or list.
EXAMPLES:
Primitive lists:
>>> from mdstools.converters.flatten import is_primitive_list >>> is_primitive_list(['a', 'b', 'c']) True >>> is_primitive_list([1, 2, 3]) True >>> is_primitive_list([1, 'mixed', 3.14, True, None]) True
Non-primitive lists:
>>> is_primitive_list([{'key': 'value'}]) False >>> is_primitive_list([[1, 2], [3, 4]]) False >>> is_primitive_list([1, {'nested': True}]) False
Edge case - empty list:
>>> is_primitive_list([]) True
Functions for unflattening tabular data back into nested structures.
- mdstools.converters.unflatten.unflatten(rows)
Reconstruct a nested dictionary from flattened rows.
Takes a list of
[number, key, value]rows produced byflatten()and rebuilds the original nested dictionary. Header rows (['number', 'key', 'value']) are automatically detected and skipped.- Parameters:
rows – List of [number, key, value] rows
- Returns:
Reconstructed nested dictionary
EXAMPLES:
Simple key-value pairs:
>>> from mdstools.converters.unflatten import unflatten >>> rows = [['1', 'name', 'test'], ['2', 'value', 42]] >>> unflatten(rows) {'name': 'test', 'value': 42}
Nested dictionaries:
>>> rows = [['1', 'experiment', '<nested>'], ... ['1.1', 'value', 42], ... ['1.2', 'units', 'mV']] >>> unflatten(rows) {'experiment': {'value': 42, 'units': 'mV'}}
Lists of dictionaries (item-indexed with i<n>):
>>> rows = [['1', 'people', '<nested>'], ... ['1.i1.1', 'name', 'Alice'], ... ['1.i1.2', 'role', 'curator'], ... ['1.i2.1', 'name', 'Bob'], ... ['1.i2.2', 'role', 'reviewer']] >>> unflatten(rows) {'people': [{'name': 'Alice', 'role': 'curator'}, {'name': 'Bob', 'role': 'reviewer'}]}
Primitive lists:
>>> rows = [['1', 'tags', '<nested>'], ... ['1.i1', '', 'alpha'], ... ['1.i2', '', 'beta'], ... ['1.i3', '', 'gamma']] >>> unflatten(rows) {'tags': ['alpha', 'beta', 'gamma']}
Mixed nested structures (dicts inside lists inside dicts):
>>> rows = [['1', 'experiment', '<nested>'], ... ['1.i1.1', 'A', '<nested>'], ... ['1.i1.1.1', 'value', 1], ... ['1.i1.1.2', 'units', 'mV'], ... ['1.i1.2', 'B', 2], ... ['1.i2.1', 'A', 3], ... ['1.i2.2', 'B', 4]] >>> unflatten(rows) {'experiment': [{'A': {'value': 1, 'units': 'mV'}, 'B': 2}, {'A': 3, 'B': 4}]}
Header rows are automatically skipped:
>>> rows = [['number', 'key', 'value'], ... ['1', 'name', 'test']] >>> unflatten(rows) {'name': 'test'}
Empty input returns an empty dict:
>>> unflatten([]) {}
Roundtrip with
flatten():>>> from mdstools.converters.flatten import flatten >>> original = {'curation': {'process': [{'role': 'curator', 'name': 'Jane'}]}} >>> unflatten(flatten(original)) == original True