Skip to content

collections

Custom data structures and related functions.

Classes

FlattenKeyDictView

FlattenKeyDictView(
    *args, flat_key_separator: str = ".", **kwargs
)

Bases: dict

Dictionary view which works with flatten keys.

This class allows accessing values of a normal Python nested dictionary using flatten keys, e.g. a.b.c, parent.child. The dictionary view implements getting, setting, deleting and checking existance of keys.

Example usage:

from ipsl_common.collections import FlattenKeyDictView

d = {
    "a": {
        "k1": 1,
        "k2": 2
    }
}
fd = FlattenKeyDictView(d)
fd["a.k1"] = 17
del fd["a.k2"]
fd["b.k1"] = 34
print(fd)

Which prints the following result:

{'a': {'k1': 17}, 'b': {'k1': 34}}

Create flatten-key dict view class.

Parameters:

  • *args

    positional arguments passed to the dict() constructor

  • flat_key_separator

    (str, default: '.' ) –

    separator of keys in the flat key (default: .)

  • **kwargs

    keyword arguments passed to the dict() constructor

Source code in ipsl_common/collections.py
63
64
65
66
67
68
69
70
71
72
def __init__(self, *args, flat_key_separator: str = ".", **kwargs) -> None:
    """Create flatten-key dict view class.

    Args:
        *args: positional arguments passed to the dict() constructor
        flat_key_separator: separator of keys in the flat key (default: `.`)
        **kwargs: keyword arguments passed to the dict() constructor
    """
    self.flat_key_separator = flat_key_separator
    super().__init__(*args, **kwargs)

Attributes

flat_key_separator instance-attribute
flat_key_separator = flat_key_separator

Methods:

__contains__
__contains__(flat_key: object) -> bool

Check if flat key exists

Source code in ipsl_common/collections.py
 97
 98
 99
100
101
102
103
104
105
def __contains__(self, flat_key: object) -> bool:
    """Check if flat key exists"""
    if not isinstance(flat_key, str):
        raise TypeError(f"Flat key must be a str, and not: {flat_key}")
    try:
        parent, last = self._resolve_parent(flat_key)
        return dict.__contains__(parent, last)
    except KeyError:
        return False
__delitem__
__delitem__(flat_key: str) -> None

Delete key-value pairs using flat key

Source code in ipsl_common/collections.py
92
93
94
95
def __delitem__(self, flat_key: str) -> None:
    """Delete key-value pairs using flat key"""
    parent, last = self._resolve_parent(flat_key)
    dict.__delitem__(parent, last)
__getitem__
__getitem__(flat_key: str) -> Any

Retrieve value using flat key

Source code in ipsl_common/collections.py
82
83
84
85
def __getitem__(self, flat_key: str) -> Any:
    """Retrieve value using flat key"""
    parent, last = self._resolve_parent(flat_key)
    return dict.__getitem__(parent, last)
__setitem__
__setitem__(flat_key: str, value: Any) -> None

Set new value using flat key

Source code in ipsl_common/collections.py
87
88
89
90
def __setitem__(self, flat_key: str, value: Any) -> None:
    """Set new value using flat key"""
    parent, last = self._resolve_parent(flat_key, create_if_missing=True)
    dict.__setitem__(parent, last, value)
ordered_keys
ordered_keys() -> list[str]

Ordered list of all flatten keys (including all parent keys)

Source code in ipsl_common/collections.py
74
75
76
def ordered_keys(self) -> list[str]:
    """Ordered list of all flatten keys (including all parent keys)"""
    return self._flatten_keys(self)
ordered_leaf_keys
ordered_leaf_keys() -> list[str]

Ordered list of flatten leaf keys (excluding all parent keys)

Source code in ipsl_common/collections.py
78
79
80
def ordered_leaf_keys(self) -> list[str]:
    """Ordered list of flatten leaf keys (excluding all parent keys)"""
    return self._flatten_keys(self, only_leafs=True)

Functions:

deep_update

deep_update(target: dict, update: dict) -> dict

Deep update of a dictionary.

Update the target dictionary in a nested manner. The standard dict.update() method performs only a shallow update, meaning that only the top-level dictionary keys are updated. This function will recursively inspect the dict values, so that the nested values are correctly updated.

This function doesn't perform any deep copy before updating the target dictionary. Hence, all the updates on the target variable are performed in-place.

Parameters:

  • target

    (dict) –

    the dictionary to update

  • update

    (dict) –

    modifications to apply

Returns:

  • dict ( dict ) –

    returned updated dictionary (the same as the target argument reference)

Source code in ipsl_common/collections.py
 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
def deep_update(target: dict, update: dict) -> dict:
    """Deep update of a dictionary.

    Update the target dictionary in a nested manner. The standard dict.update()
    method performs only a shallow update, meaning that only the top-level dictionary
    keys are updated. This function will recursively inspect the dict values,
    so that the nested values are correctly updated.

    This function doesn't perform any deep copy before updating the target dictionary.
    Hence, all the updates on the `target` variable are performed in-place.

    Args:
        target: the dictionary to update
        update: modifications to apply

    Returns:
        dict: returned updated dictionary (the same as the `target` argument reference)
    """
    for key, value in update.items():
        # If they key exists and its value is a dictionary in both,
        # the target and the update, then perform deep update on the value
        if key in target and isinstance(target[key], dict) and isinstance(value, dict):
            deep_update(target[key], value)
        # Otherwise, it's an unseen value or the updated value is a non-dict.
        else:
            target[key] = value
    return target