# i2.chain_map

Merge mappings

Marked for deprecation.

### Functions

| [`is_iterable`](#i2.chain_map.is_iterable)(x)          | Similar in nature to [`callable()`](https://docs.python.org/3/builtins/functions.html#callable), `is_iterable` returns `True` if an object is iterable, `False` if not.   |
|--------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `is_mapping`(x)                                                          |                                                                                                                                                                           |
| `not_mapping`(x)                                                         |                                                                                                                                                                           |
| [`unique_iter`](#i2.chain_map.unique_iter)(src[, key]) | Yield unique elements from the iterable, *src*, based on *key*, in the order in which they first appeared in *src*.                                                       |

### Classes

| [`ChainMapTree`](#i2.chain_map.ChainMapTree)(\*maps)   | Combine/overlay multiple hierarchical mappings.   |
|-------------------------------------------------------------------------|---------------------------------------------------|

### *class* i2.chain_map.ChainMapTree(\*maps)

Bases: [`Mapping`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Mapping)

Combine/overlay multiple hierarchical mappings. This efficiently merges
multiple hierarchical (could be several layers deep) dictionaries, producing
a new view into them that acts exactly like a merged dictionary, but without
doing any copying.
Because it doesn’t actually copy the data, it is intended to be used only
with immutable mappings. It is safe to change *leaf* data values,
and the results will be reflected here, but changing the structure of any
of the trees will not work.

```pycon
>>> base1 = {
...     'a1': 'base1.a1',
...     'a2': 'base1.a2',
...     'a3': {
...         'b1': 'base1.a3.b1',
...         'b2': 'base1.a3.b2',
...     },
... }
>>> base2 = {
...     'a2': 'base2.a2',
...     'a3': {
...         'b2': 'base2.a3.b2',
...         'b4': 'base2.a3.b4',
...     },
...     'a4': 'base2.a4',
... }
>>>
>>> cm = ChainMapTree(base1, base2)
>>> cm['a1']
'base1.a1'
>>> cm['a2']
'base1.a2'
>>> cm['a4']
'base2.a4'
>>> cm['a3']
ChainMapTree({'b1': 'base1.a3.b1', 'b2': 'base1.a3.b2'}, {'b2': 'base2.a3.b2', 'b4': 'base2.a3.b4'})
>>> cm['a3']['b1']
'base1.a3.b1'
>>> cm['a3']['b4']
'base2.a3.b4'
>>> cm = ChainMapTree(base2, base1)
>>> cm['a1']
'base1.a1'
>>> cm['a2']
'base2.a2'
>>> cm['a4']
'base2.a4'
>>> cm['a3']
ChainMapTree({'b2': 'base2.a3.b2', 'b4': 'base2.a3.b4'}, {'b1': 'base1.a3.b1', 'b2': 'base1.a3.b2'})
>>> cm['a3']['b2']
'base2.a3.b2'
>>> cm['a3']['b1']
'base1.a3.b1'
>>>
>>> # Let's do a ChainMapTree with THREE bases now!
>>> base3 = {
...     'a2': 'base3.a2',
...     'a3': {
...         'b2': 'base3.a3.b2',
...         'b4': 'base3.a3.b4',
...     },
...     'a4': 'base3.a4',
... }
>>> cm = ChainMapTree(base3, base2, base1)
>>> cm['a2']  # will get it from base3
'base3.a2'
>>> cm['a3']['b2']  # will get it from base3 (not base2)
'base3.a3.b2'
>>> cm['a3']['b1']  # will get it from base1 (since no one else has it)
'base1.a3.b1'
```

Based on: [https://gist.github.com/Klortho/7d83975559bdcc47ac64fd7d877934f6](https://gist.github.com/Klortho/7d83975559bdcc47ac64fd7d877934f6)

#### to_dict()

Convert to dict

```pycon
>>> a = {'a': {'x': 1, 'z': 3}, 'foo': "a's foo"}
>>> b = {'a': {'y': 222, 'z': 333}, 'foo': "b's foo"}
>>> cm = ChainMapTree(a, b)
>>> # It acts like a dict when you ask for items, but is not a dict. If you want a dict, do this:
>>> cm.to_dict()
{'a': {'x': 1, 'z': 3, 'y': 222}, 'foo': "a's foo"}
>>> # Compare to normal/flat/not-nested chaining:
>>> dict(a, **b)   # Note the precedence is the inverse of ChainMapTree!
{'a': {'y': 222, 'z': 333}, 'foo': "b's foo"}
>>>
>>> # See what you get if you specify b before a
>>> ChainMapTree(b, a).to_dict()
{'a': {'y': 222, 'z': 333, 'x': 1}, 'foo': "b's foo"}
>>> # Compare to normal/flat/not-nested chaining:
>>> dict(b, **a)  # Note the precedence is the inverse of ChainMapTree!
{'a': {'x': 1, 'z': 3}, 'foo': "a's foo"}
```

### i2.chain_map.is_iterable(x)

Similar in nature to [`callable()`](https://docs.python.org/3/builtins/functions.html#callable), `is_iterable` returns
`True` if an object is iterable, `False` if not.

```pycon
>>> is_iterable([])
True
>>> is_iterable(1)
False
```

### i2.chain_map.unique_iter(src, key=None)

Yield unique elements from the iterable, *src*, based on *key*,
in the order in which they first appeared in *src*.

```pycon
>>> repetitious = [1, 2, 3] * 10
>>> list(unique_iter(repetitious))
[1, 2, 3]
```

By default, *key* is the object itself, but *key* can either be a
callable or, for convenience, a string name of the attribute on
which to uniqueify objects, falling back on identity when the
attribute is not present.

```pycon
>>> pleasantries = ['hi', 'hello', 'ok', 'bye', 'yes']
>>> list(unique_iter(pleasantries, key=lambda x: len(x)))
['hi', 'hello', 'bye']
```
