]>
Commit | Line | Data |
---|---|---|
11fdf7f2 | 1 | # -*- coding: utf-8 -*- |
11fdf7f2 TL |
2 | |
3 | try: | |
f67539c2 | 4 | from typing import Any, Dict |
11fdf7f2 TL |
5 | except ImportError: |
6 | pass | |
7 | ||
8 | ||
9 | def update_dict(data, update_data): | |
10 | # type: (Dict[Any, Any], Dict[Any, Any]) -> Dict[Any] | |
11 | """ Update a dictionary recursively. | |
12 | ||
13 | Eases doing so by providing the option to separate the key to be updated by dot characters. If | |
14 | a key provided does not exist, it will raise an KeyError instead of just updating the | |
15 | dictionary. | |
16 | ||
17 | Limitations | |
18 | ||
19 | Please note that the functionality provided by this method can only be used if the dictionary to | |
20 | be updated (`data`) does not contain dot characters in its keys. | |
21 | ||
22 | :raises KeyError: | |
23 | ||
24 | >>> update_dict({'foo': {'bar': 5}}, {'foo.bar': 10}) | |
25 | {'foo': {'bar': 10}} | |
26 | ||
27 | >>> update_dict({'foo': {'bar': 5}}, {'xyz': 10}) | |
28 | Traceback (most recent call last): | |
29 | ... | |
30 | KeyError: 'xyz' | |
31 | ||
32 | >>> update_dict({'foo': {'bar': 5}}, {'foo.xyz': 10}) | |
33 | Traceback (most recent call last): | |
34 | ... | |
35 | KeyError: 'xyz' | |
36 | """ | |
37 | for k, v in update_data.items(): | |
38 | keys = k.split('.') | |
39 | element = None | |
40 | for i, key in enumerate(keys): | |
41 | last = False | |
42 | if len(keys) == i + 1: | |
43 | last = True | |
44 | ||
45 | if not element: | |
46 | element = data[key] | |
47 | elif not last: | |
48 | element = element[key] # pylint: disable=unsubscriptable-object | |
49 | ||
50 | if last: | |
51 | if key not in element: | |
52 | raise KeyError(key) | |
53 | ||
54 | element[key] = v | |
55 | return data |