blob: 3cfb99e62165ebbadaa18fac2dbca8f8828b4563 [file] [log] [blame]
#
# Copyright (c) 2021 Project CHIP Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
"""Nested dictionary utilities."""
from typing import Any, Mapping, MutableMapping, Optional, Sequence
Key = Sequence
def get(nd: Optional[Mapping], keys: Key, default: Any = None) -> Any:
"""Get a value from a nested dictionary."""
d: Any = nd
while d and keys:
d = d.get(keys[0])
keys = keys[1:]
if d is not None and d != {}:
return d
if default is not None:
return default
return d
def put(nd: MutableMapping, keys: Key, value: Any) -> None:
"""Store a value in a nested dictionary."""
while True:
key = keys[0]
keys = keys[1:]
if not keys:
break
if key not in nd:
nd[key] = {}
nd = nd[key]
nd[key] = value
def store(nd: MutableMapping, keys: Key, value: Any, empty: Any, add) -> None:
"""Store a value in a nested dictionary where the leaves are containers."""
while True:
key = keys[0]
keys = keys[1:]
if not keys:
break
if key not in nd:
nd[key] = {}
nd = nd[key]
if key not in nd:
nd[key] = empty
add(nd[key], value)
def update(nd: MutableMapping, src: Mapping) -> None:
"""Update a nested dictionary."""
for k, v in src.items():
if k not in nd or nd[k] is None:
nd[k] = v
elif isinstance(nd[k], dict) and isinstance(v, dict):
update(nd[k], v)
elif isinstance(nd[k], list):
if isinstance(v, list):
nd[k] += v
else:
nd[k].append(v)
elif type(nd[k]) == type(v):
nd[k] = v
else:
raise TypeError(f"type mismatch {k},{v} was {nd[k]}")