#################################################
### THIS FILE WAS AUTOGENERATED! DO NOT EDIT! ###
#################################################
# file to edit: ./nb/ConstraintDict.ipynb
import sys
if __name__ == '__main__': sys.path.append('..')
import xs_lib.common as common

import operator
class ConstraintDict(dict):
    def __init__(self, arg1: dict or str or list, default_value=None):
        """
        通过str, list来设定可选key列表，初始化为default_value
        或者通过dict初始化，但不允许出现新的key
        """
        if isinstance(arg1, dict):
            self._names = set(arg1.keys())
            super().__init__(arg1)
            return

        if isinstance(arg1, str):
            names = self.parse_names(arg1)
        elif isinstance(arg1, list):
            pass
        else :
            raise TypeError(f"{type(arg1)} not allowed")
        self._names = set(names)
        super().__init__(dict.fromkeys(names, default_value))

    def __setitem__(self, key, val):
        assert key in self._names, f"{key} not in {self._names}"
        super().__setitem__(key, val)

    @staticmethod
    def parse_names(names: list or str):
        if isinstance(names, list):return names
        assert isinstance(names, str), f"{type(names)} not valid"
        names = names.split(',')
        names = map(lambda s:s.strip(), names)
        names = filter(lambda x:len(x)>0, names)
        names = list(names)
        return names

    def update(self, d:dict):
        _names = self._names
        for k in d: assert k in _names , f"key '{k}' not in {_names}"
        super().update(d)

    def subdict(self, names):
        """
        names:list or str split by ','
        继承self._names，但是用names代替self._names
        """
        names = self.parse_names(names)
        vals = self.gets(names)
        new_dict = self.__class__(names)
        new_dict.update(dict(names, vals))
        return new_dict

    def gets(self, names: list or str):
        """
        names:list or str split by ','
        """
        names = self.parse_names(names)
        vals = operator.itemgetter(*names)(self)
        return vals
