1#   Copyright 2016 - Google, Inc.
2#
3#   Licensed under the Apache License, Version 2.0 (the "License");
4#   you may not use this file except in compliance with the License.
5#   You may obtain a copy of the License at
6#
7#       http://www.apache.org/licenses/LICENSE-2.0
8#
9#   Unless required by applicable law or agreed to in writing, software
10#   distributed under the License is distributed on an "AS IS" BASIS,
11#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12#   See the License for the specific language governing permissions and
13#   limitations under the License.
14
15
16class DataWrapper(object):
17    """A special type of packed data.
18
19    This is the base class for a type of data that wraps around another set
20    of data. This data will be unpacked on every read right before the real
21    value is needed. When unpacked the wrapper can perform special operations
22    to get the real data.
23    """
24
25    def get_real_value(self, unwrapper):
26        """Unpacks the data from the wrapper.
27
28        Args:
29            unwrapper: The object calling the unwrapping.
30
31        Returns:
32            The real value stored in the data wrapper.
33        """
34        value = self.unwrap(unwrapper)
35        while isinstance(value, DataWrapper):
36            value = value.unwrap(unwrapper)
37
38        return value
39
40    def unwrap(self, unwrapper):
41        """Unwraps the data from this wrapper and this wrapper only.
42
43        Unlike get_real_value, this method is abstract and is where user
44        code can be written to unpack the data value. If this returns
45        another data wrapper then get_real_value will continue to unwrap
46        until a true value is given.
47
48        Args:
49            unwrapper: The object calling the unwrapping.
50
51        Returns:
52            The unwrapped data.
53        """
54        pass
55
56
57class ConfigWrapper(object):
58    """Object used to asses config values.
59
60    Base class for all objects that wrap around the configs loaded into the
61    application.
62    """
63
64    def get_value(self, key):
65        """Reads the value of a config at a certain key.
66
67        Args:
68            key: The key of the value to read.
69
70        Returns:
71            The raw value stored at that key.
72        """
73        raise NotImplementedError()
74
75    def set_value(self, key, value):
76        """Writes a new value into the config at a certain key.
77
78        Args:
79            key: The key to write the value at.
80            value: The new value to store at that key.
81        """
82        raise NotImplementedError()
83
84    def has_value(self, key):
85        """Checks if this config has a certain key.
86
87        Args:
88            key: The key to check for.
89
90        Returns:
91            True if the key exists.
92        """
93        raise NotImplementedError()
94
95    def keys(self):
96        """Gets all keys in this config.
97
98        Returns:
99            An iterator (or some iterable object) with all keys in this config.
100        """
101        raise NotImplementedError()
102
103    def __getitem__(self, key):
104        """Overrides the bracket accessor to read a value.
105
106        Unlike get_value, this will return the true value of a config. This
107        will unpack any data wrappers.
108
109        Args:
110            key: The key to read.
111
112        Returns:
113            The true value stored at the key.
114        """
115        value = self.get_value(key)
116        if isinstance(value, DataWrapper):
117            return value.get_real_value(self)
118        else:
119            return value
120
121    def __setitem__(self, key, value):
122        """Overrides the bracket accessor to write a value.
123
124        Args:
125            key: The key to write to.
126        """
127        return self.set_value(key, value)
128
129    def __iter__(self):
130        """Iterates over all values in the config.
131
132        Returns:
133            An iterator of key, value pairs.
134        """
135        for key in self.keys():
136            yield (key, self[key])
137