Introducing pyobmc

We have openbmc python utilities scattered all over the place.  To
facilitate reuse, bring them together in a single python package.

None of this is new code, it was all simply ported and re-arranged
from other projects.

Ran everything through pep8.
diff --git a/obmc/utils/__init__.py b/obmc/utils/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/obmc/utils/__init__.py
diff --git a/obmc/utils/misc.py b/obmc/utils/misc.py
new file mode 100644
index 0000000..cfde266
--- /dev/null
+++ b/obmc/utils/misc.py
@@ -0,0 +1,63 @@
+# Contributors Listed Below - COPYRIGHT 2016
+# [+] International Business Machines Corp.
+#
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+
+
+class Path:
+    def __init__(self, path):
+        self.parts = filter(bool, path.split('/'))
+
+    def rel(self, first=None, last=None):
+        # relative
+        return self.get('', first, last)
+
+    def fq(self, first=None, last=None):
+        # fully qualified
+        return self.get('/', first, last)
+
+    def depth(self):
+        return len(self.parts)
+
+    def get(self, prefix='/', first=None, last=None):
+        if not first:
+            first = 0
+        if not last:
+            last = self.depth()
+        return prefix + '/'.join(self.parts[first:last])
+
+
+def org_dot_openbmc_match(name):
+    return 'org.openbmc' in name
+
+
+class ListMatch(object):
+    def __init__(self, l):
+        self.l = l
+
+    def __call__(self, match):
+        return match in self.l
+
+
+def find_case_insensitive(value, lst):
+    return next((x for x in lst if x.lower() == value.lower()), None)
+
+
+def makelist(data):
+    if isinstance(data, list):
+            return data
+    elif data:
+            return [data]
+    else:
+            return []
diff --git a/obmc/utils/pathtree.py b/obmc/utils/pathtree.py
new file mode 100644
index 0000000..221495e
--- /dev/null
+++ b/obmc/utils/pathtree.py
@@ -0,0 +1,183 @@
+# Contributors Listed Below - COPYRIGHT 2016
+# [+] International Business Machines Corp.
+#
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+
+
+class PathTreeItemIterator(object):
+    def __init__(self, path_tree, subtree, depth):
+        self.path_tree = path_tree
+        self.path = []
+        self.itlist = []
+        self.subtree = ['/'] + filter(bool, subtree.split('/'))
+        self.depth = depth
+        d = path_tree.root
+        for k in self.subtree:
+            try:
+                d = d[k]['children']
+            except KeyError:
+                raise KeyError(subtree)
+        self.it = d.iteritems()
+
+    def __iter__(self):
+        return self
+
+    def __next__(self):
+        return super(PathTreeItemIterator, self).next()
+
+    def next(self):
+        key, value = self._next()
+        path = self.subtree[0] + '/'.join(self.subtree[1:] + self.path)
+        return path, value.get('data')
+
+    def _next(self):
+        try:
+            while True:
+                x = self.it.next()
+                depth_exceeded = len(self.path) + 1 > self.depth
+                if self.depth and depth_exceeded:
+                    continue
+                self.itlist.append(self.it)
+                self.path.append(x[0])
+                self.it = x[1]['children'].iteritems()
+                break
+
+        except StopIteration:
+            if not self.itlist:
+                raise StopIteration
+
+            self.it = self.itlist.pop()
+            self.path.pop()
+            x = self._next()
+
+        return x
+
+
+class PathTreeKeyIterator(PathTreeItemIterator):
+    def __init__(self, path_tree, subtree, depth):
+        super(PathTreeKeyIterator, self).__init__(path_tree, subtree, depth)
+
+    def next(self):
+        return super(PathTreeKeyIterator, self).next()[0]
+
+
+class PathTree:
+    def __init__(self):
+        self.root = {}
+
+    def _try_delete_parent(self, elements):
+        if len(elements) == 1:
+            return False
+
+        kids = 'children'
+        elements.pop()
+        d = self.root
+        for k in elements[:-1]:
+            d = d[k][kids]
+
+        if 'data' not in d[elements[-1]] and not d[elements[-1]][kids]:
+            del d[elements[-1]]
+            self._try_delete_parent(elements)
+
+    def _get_node(self, key):
+        kids = 'children'
+        elements = ['/'] + filter(bool, key.split('/'))
+        d = self.root
+        for k in elements[:-1]:
+            try:
+                d = d[k][kids]
+            except KeyError:
+                raise KeyError(key)
+
+        return d[elements[-1]]
+
+    def __iter__(self):
+        return self
+
+    def __missing__(self, key):
+        for x in self.iterkeys():
+            if key == x:
+                return False
+        return True
+
+    def __delitem__(self, key):
+        kids = 'children'
+        elements = ['/'] + filter(bool, key.split('/'))
+        d = self.root
+        for k in elements[:-1]:
+            try:
+                d = d[k][kids]
+            except KeyError:
+                raise KeyError(key)
+
+        del d[elements[-1]]
+        self._try_delete_parent(elements)
+
+    def __setitem__(self, key, value):
+        kids = 'children'
+        elements = ['/'] + filter(bool, key.split('/'))
+        d = self.root
+        for k in elements[:-1]:
+            d = d.setdefault(k, {kids: {}})[kids]
+
+        children = d.setdefault(elements[-1], {kids: {}})[kids]
+        d[elements[-1]].update({kids: children, 'data': value})
+
+    def __getitem__(self, key):
+        return self._get_node(key).get('data')
+
+    def setdefault(self, key, default):
+        if not self.get(key):
+            self.__setitem__(key, default)
+
+        return self.__getitem__(key)
+
+    def get(self, key, default=None):
+        try:
+            x = self.__getitem__(key)
+        except KeyError:
+            x = default
+
+        return x
+
+    def get_children(self, key):
+        return [x for x in self._get_node(key)['children'].iterkeys()]
+
+    def demote(self, key):
+        n = self._get_node(key)
+        if 'data' in n:
+            del n['data']
+
+    def keys(self, subtree='/', depth=None):
+        return [x for x in self.iterkeys(subtree, depth)]
+
+    def values(self, subtree='/', depth=None):
+        return [x[1] for x in self.iteritems(subtree, depth)]
+
+    def items(self, subtree='/', depth=None):
+        return [x for x in self.iteritems(subtree, depth)]
+
+    def dataitems(self, subtree='/', depth=None):
+        return [x for x in self.iteritems(subtree, depth)
+                if x[1] is not None]
+
+    def iterkeys(self, subtree='/', depth=None):
+        if not self.root:
+            return {}.iterkeys()
+        return PathTreeKeyIterator(self, subtree, depth)
+
+    def iteritems(self, subtree='/', depth=None):
+        if not self.root:
+            return {}.iteritems()
+        return PathTreeItemIterator(self, subtree, depth)