"""Base class for chaining DBs"""importitertoolsimporttypingastpfromcollectionsimportChainMapfromcollections.abcimportMutableMapping,MutableSequence,MutableSet
[docs]classChainDBDefaultType:"""Singleton for representing when no default value is given."""__inst:tp.Optional["ChainDBDefaultType"]=Nonedef__new__(cls):ifChainDBDefaultType.__instisNone:ChainDBDefaultType.__inst=object.__new__(cls)returnChainDBDefaultType.__inst
ChainDBDefault=ChainDBDefaultType()
[docs]classChainDB(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=Noneresults=[]# Try to get all the data from all the mappingsformappinginself.maps:results.append(mapping.get(key,ChainDBDefault))# if all the results are mapping create a ChainDBifall([isinstance(result,MutableMapping)forresultinresults]):forresultinresults:ifresisNone:res=ChainDB(result)else:res.maps.append(result)elifall([isinstance(result,(MutableSequence,MutableSet))forresultinresults]):results_chain=itertools.chain(*results)# if all reults have the same type, cast into that typeifall([isinstance(result,type(results[0]))forresultinresults]):returntype(results[0])(results_chain)else:returnlist(results_chain)else:forresultinreversed(results):ifresultisnotChainDBDefault:returnresultraiseKeyError(f"{key} is none of the current mappings")returnresdef__setitem__(self,key,value):ifkeynotinself:super().__setitem__(key,value)else:# Try to get all the data from all the mappingsformappinginreversed(self.maps):ifkeyinmapping:mapping[key]=value