blob: dc48609af48c68869467882fe522866e2e1b9fe8 [file] [log] [blame]
Brad Bishop8ffe1e42016-02-11 16:15:40 -05001# Contributors Listed Below - COPYRIGHT 2016
2# [+] International Business Machines Corp.
3#
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
14# implied. See the License for the specific language governing
15# permissions and limitations under the License.
16
17
18class PathTreeItemIterator(object):
19 def __init__(self, path_tree, subtree, depth):
20 self.path_tree = path_tree
21 self.path = []
22 self.itlist = []
CamVan Nguyendc63ed42018-03-07 18:25:21 -060023 self.subtree = ['/'] + list(filter(bool, subtree.split('/')))
Brad Bishop8ffe1e42016-02-11 16:15:40 -050024 self.depth = depth
25 d = path_tree.root
26 for k in self.subtree:
27 try:
28 d = d[k]['children']
29 except KeyError:
30 raise KeyError(subtree)
CamVan Nguyendc63ed42018-03-07 18:25:21 -060031 # TODO: openbmc/openbmc#2994 remove python 2 support
32 try: # python 2
33 self.it = d.iteritems()
34 except AttributeError: # python 3
35 self.it = iter(d.items())
Brad Bishop8ffe1e42016-02-11 16:15:40 -050036
37 def __iter__(self):
38 return self
39
CamVan Nguyendc63ed42018-03-07 18:25:21 -060040 # TODO: openbmc/openbmc#2994 remove python 2 support
41 # python 2
Brad Bishopd641c082018-01-31 15:55:58 -050042 def next(self):
Brad Bishop8ffe1e42016-02-11 16:15:40 -050043 key, value = self._next()
44 path = self.subtree[0] + '/'.join(self.subtree[1:] + self.path)
45 return path, value.get('data')
46
CamVan Nguyendc63ed42018-03-07 18:25:21 -060047 # python 3
48 import sys
49 if sys.version_info[0] > 2:
50 __next__ = next
51
Brad Bishop8ffe1e42016-02-11 16:15:40 -050052 def _next(self):
53 try:
54 while True:
CamVan Nguyendc63ed42018-03-07 18:25:21 -060055 x = next(self.it)
Andrew Jeffery786e6a62018-05-04 23:03:50 +093056 if self.depth:
57 if len(self.path) + 1 > self.depth:
58 continue
Brad Bishop8ffe1e42016-02-11 16:15:40 -050059 self.itlist.append(self.it)
60 self.path.append(x[0])
CamVan Nguyendc63ed42018-03-07 18:25:21 -060061 # TODO: openbmc/openbmc#2994 remove python 2 support
62 try: # python 2
63 self.it = x[1]['children'].iteritems()
64 except AttributeError: # python 3
65 self.it = iter(x[1]['children'].items())
Brad Bishop8ffe1e42016-02-11 16:15:40 -050066 break
67
68 except StopIteration:
69 if not self.itlist:
70 raise StopIteration
71
72 self.it = self.itlist.pop()
73 self.path.pop()
74 x = self._next()
75
76 return x
77
78
79class PathTreeKeyIterator(PathTreeItemIterator):
80 def __init__(self, path_tree, subtree, depth):
81 super(PathTreeKeyIterator, self).__init__(path_tree, subtree, depth)
82
CamVan Nguyendc63ed42018-03-07 18:25:21 -060083 # TODO: openbmc/openbmc#2994 remove python 2 support
84 # python 2
Brad Bishopd641c082018-01-31 15:55:58 -050085 def next(self):
Brad Bishop8ffe1e42016-02-11 16:15:40 -050086 return super(PathTreeKeyIterator, self).next()[0]
87
CamVan Nguyendc63ed42018-03-07 18:25:21 -060088 # python 3
89 import sys
90 if sys.version_info[0] > 2:
91 __next__ = next
92
Brad Bishop8ffe1e42016-02-11 16:15:40 -050093
94class PathTree:
95 def __init__(self):
96 self.root = {}
Andrew Jeffery52aeb312018-05-08 11:36:19 +093097 self.cache = {}
Brad Bishop8ffe1e42016-02-11 16:15:40 -050098
99 def _try_delete_parent(self, elements):
100 if len(elements) == 1:
101 return False
102
103 kids = 'children'
104 elements.pop()
105 d = self.root
106 for k in elements[:-1]:
107 d = d[k][kids]
108
109 if 'data' not in d[elements[-1]] and not d[elements[-1]][kids]:
110 del d[elements[-1]]
111 self._try_delete_parent(elements)
112
113 def _get_node(self, key):
114 kids = 'children'
CamVan Nguyendc63ed42018-03-07 18:25:21 -0600115 elements = ['/'] + list(filter(bool, key.split('/')))
Brad Bishop8ffe1e42016-02-11 16:15:40 -0500116 d = self.root
117 for k in elements[:-1]:
118 try:
119 d = d[k][kids]
120 except KeyError:
121 raise KeyError(key)
122
123 return d[elements[-1]]
124
125 def __iter__(self):
Andrew Jeffery786e6a62018-05-04 23:03:50 +0930126 return PathTreeItemIterator(self, '/', None)
Brad Bishop8ffe1e42016-02-11 16:15:40 -0500127
128 def __missing__(self, key):
Brad Bishopd641c082018-01-31 15:55:58 -0500129 for x in self.iterkeys():
Brad Bishop8ffe1e42016-02-11 16:15:40 -0500130 if key == x:
131 return False
132 return True
133
134 def __delitem__(self, key):
Andrew Jeffery52aeb312018-05-08 11:36:19 +0930135 del self.cache[key]
Brad Bishop8ffe1e42016-02-11 16:15:40 -0500136 kids = 'children'
CamVan Nguyendc63ed42018-03-07 18:25:21 -0600137 elements = ['/'] + list(filter(bool, key.split('/')))
Brad Bishop8ffe1e42016-02-11 16:15:40 -0500138 d = self.root
139 for k in elements[:-1]:
140 try:
141 d = d[k][kids]
142 except KeyError:
143 raise KeyError(key)
144
145 del d[elements[-1]]
146 self._try_delete_parent(elements)
147
148 def __setitem__(self, key, value):
Andrew Jeffery52aeb312018-05-08 11:36:19 +0930149 self.cache[key] = value
Brad Bishop8ffe1e42016-02-11 16:15:40 -0500150 kids = 'children'
CamVan Nguyendc63ed42018-03-07 18:25:21 -0600151 elements = ['/'] + list(filter(bool, key.split('/')))
Brad Bishop8ffe1e42016-02-11 16:15:40 -0500152 d = self.root
153 for k in elements[:-1]:
154 d = d.setdefault(k, {kids: {}})[kids]
155
156 children = d.setdefault(elements[-1], {kids: {}})[kids]
157 d[elements[-1]].update({kids: children, 'data': value})
158
159 def __getitem__(self, key):
Andrew Jeffery52aeb312018-05-08 11:36:19 +0930160 return self.cache[key]
Brad Bishop8ffe1e42016-02-11 16:15:40 -0500161
162 def setdefault(self, key, default):
163 if not self.get(key):
164 self.__setitem__(key, default)
165
166 return self.__getitem__(key)
167
168 def get(self, key, default=None):
169 try:
170 x = self.__getitem__(key)
171 except KeyError:
172 x = default
173
174 return x
175
176 def get_children(self, key):
CamVan Nguyendc63ed42018-03-07 18:25:21 -0600177 return [x for x in self._get_node(key)['children'].keys()]
Brad Bishop8ffe1e42016-02-11 16:15:40 -0500178
179 def demote(self, key):
180 n = self._get_node(key)
181 if 'data' in n:
182 del n['data']
183
184 def keys(self, subtree='/', depth=None):
185 return [x for x in self.iterkeys(subtree, depth)]
186
187 def values(self, subtree='/', depth=None):
188 return [x[1] for x in self.iteritems(subtree, depth)]
189
190 def items(self, subtree='/', depth=None):
191 return [x for x in self.iteritems(subtree, depth)]
192
193 def dataitems(self, subtree='/', depth=None):
194 return [x for x in self.iteritems(subtree, depth)
195 if x[1] is not None]
196
197 def iterkeys(self, subtree='/', depth=None):
198 if not self.root:
CamVan Nguyendc63ed42018-03-07 18:25:21 -0600199 # TODO: openbmc/openbmc#2994 remove python 2 support
200 try: # python 2
201 return {}.iterkeys()
202 except AttributeError: # python 3
203 return iter({}.keys())
Brad Bishop8ffe1e42016-02-11 16:15:40 -0500204 return PathTreeKeyIterator(self, subtree, depth)
205
206 def iteritems(self, subtree='/', depth=None):
207 if not self.root:
CamVan Nguyendc63ed42018-03-07 18:25:21 -0600208 # TODO: openbmc/openbmc#2994 remove python 2 support
209 try: # python 2
210 return {}.iteritems()
211 except AttributeError: # python 3
212 return iter({}.items())
Brad Bishop8ffe1e42016-02-11 16:15:40 -0500213 return PathTreeItemIterator(self, subtree, depth)
Brad Bishop4e601a02016-04-01 14:29:46 -0400214
215 def dumpd(self, subtree='/'):
216 result = {}
217 d = result
218
219 for k, v in self.iteritems(subtree):
CamVan Nguyendc63ed42018-03-07 18:25:21 -0600220 elements = ['/'] + list(filter(bool, k.split('/')))
Brad Bishop4e601a02016-04-01 14:29:46 -0400221 d = result
222 for k in elements:
223 d = d.setdefault(k, {})
224 if v is not None:
225 d.update(v)
226
227 return result