A dict-like configuration storage with additional support for namespaces, validators, meta-data, on_change listeners and more. This storage is optimized for fast read access. Retrieving a key or using non-altering dict methods (e.g. `dict.get()`) has no overhead com
| 2011 | |
| 2012 | |
| 2013 | class ConfigDict(dict): |
| 2014 | ''' A dict-like configuration storage with additional support for |
| 2015 | namespaces, validators, meta-data, on_change listeners and more. |
| 2016 | |
| 2017 | This storage is optimized for fast read access. Retrieving a key |
| 2018 | or using non-altering dict methods (e.g. `dict.get()`) has no overhead |
| 2019 | compared to a native dict. |
| 2020 | ''' |
| 2021 | __slots__ = ('_meta', '_on_change') |
| 2022 | |
| 2023 | class Namespace(DictMixin): |
| 2024 | |
| 2025 | def __init__(self, config, namespace): |
| 2026 | self._config = config |
| 2027 | self._prefix = namespace |
| 2028 | |
| 2029 | def __getitem__(self, key): |
| 2030 | depr('Accessing namespaces as dicts is discouraged. ' |
| 2031 | 'Only use flat item access: ' |
| 2032 | 'cfg["names"]["pace"]["key"] -> cfg["name.space.key"]') #0.12 |
| 2033 | return self._config[self._prefix + '.' + key] |
| 2034 | |
| 2035 | def __setitem__(self, key, value): |
| 2036 | self._config[self._prefix + '.' + key] = value |
| 2037 | |
| 2038 | def __delitem__(self, key): |
| 2039 | del self._config[self._prefix + '.' + key] |
| 2040 | |
| 2041 | def __iter__(self): |
| 2042 | ns_prefix = self._prefix + '.' |
| 2043 | for key in self._config: |
| 2044 | ns, dot, name = key.rpartition('.') |
| 2045 | if ns == self._prefix and name: |
| 2046 | yield name |
| 2047 | |
| 2048 | def keys(self): return [x for x in self] |
| 2049 | def __len__(self): return len(self.keys()) |
| 2050 | def __contains__(self, key): return self._prefix + '.' + key in self._config |
| 2051 | def __repr__(self): return '<Config.Namespace %s.*>' % self._prefix |
| 2052 | def __str__(self): return '<Config.Namespace %s.*>' % self._prefix |
| 2053 | |
| 2054 | # Deprecated ConfigDict features |
| 2055 | def __getattr__(self, key): |
| 2056 | depr('Attribute access is deprecated.') #0.12 |
| 2057 | if key not in self and key[0].isupper(): |
| 2058 | self[key] = ConfigDict.Namespace(self._config, self._prefix + '.' + key) |
| 2059 | if key not in self and key.startswith('__'): |
| 2060 | raise AttributeError(key) |
| 2061 | return self.get(key) |
| 2062 | |
| 2063 | def __setattr__(self, key, value): |
| 2064 | if key in ('_config', '_prefix'): |
| 2065 | self.__dict__[key] = value |
| 2066 | return |
| 2067 | depr('Attribute assignment is deprecated.') #0.12 |
| 2068 | if hasattr(DictMixin, key): |
| 2069 | raise AttributeError('Read-only attribute.') |
| 2070 | if key in self and self[key] and isinstance(self[key], self.__class__): |