Source code for xonsh.lib.collections
"""Base class for chaining DBs"""
import itertools
import typing as tp
from collections import ChainMap
from collections.abc import MutableMapping, MutableSequence, MutableSet
[docs]
class ChainDBDefaultType:
"""Singleton for representing when no default value is given."""
__inst: tp.Optional["ChainDBDefaultType"] = None
def __new__(cls):
if ChainDBDefaultType.__inst is None:
ChainDBDefaultType.__inst = object.__new__(cls)
return ChainDBDefaultType.__inst
ChainDBDefault = ChainDBDefaultType()
[docs]
class ChainDB(ChainMap):
"""A ChainMap who's ``_getitem__`` returns either a ChainDB or
the result. The results resolve to the outermost mapping."""
def __getitem__(self, key):
res = None
results = []
# Try to get all the data from all the mappings
for mapping in self.maps:
results.append(mapping.get(key, ChainDBDefault))
# if all the results are mapping create a ChainDB
if all([isinstance(result, MutableMapping) for result in results]):
for result in results:
if res is None:
res = ChainDB(result)
else:
res.maps.append(result)
elif all(
[isinstance(result, (MutableSequence, MutableSet)) for result in results]
):
results_chain = itertools.chain(*results)
# if all reults have the same type, cast into that type
if all([isinstance(result, type(results[0])) for result in results]):
return type(results[0])(results_chain)
else:
return list(results_chain)
else:
for result in reversed(results):
if result is not ChainDBDefault:
return result
raise KeyError(f"{key} is none of the current mappings")
return res
def __setitem__(self, key, value):
if key not in self:
super().__setitem__(key, value)
else:
# Try to get all the data from all the mappings
for mapping in reversed(self.maps):
if key in mapping:
mapping[key] = value
def _convert_to_dict(cm):
if isinstance(cm, (ChainMap, ChainDB)):
r = {}
for k, v in cm.items():
r[k] = _convert_to_dict(v)
return r
else:
return cm