Added Traverse Helper

Added Traverse Helper and unit-tests
Simplified generate UUID function

Change-Id: I307fc689e592b94e4e084d0e6a164e11c5ec4429
This commit is contained in:
Serg Melikyan 2013-07-08 11:17:57 +04:00
parent 5a57f15ded
commit 0790add5aa
4 changed files with 160 additions and 1 deletions

View File

@ -13,12 +13,88 @@
# under the License.
import eventlet
import types
from collections import deque
from functools import wraps
from muranoapi.openstack.common import log as logging
log = logging.getLogger(__name__)
class TraverseHelper(object):
@staticmethod
def get(path, source):
"""
Provides the ability to traverse a data source made up of any
combination of lists and dicts. Has simple rules for selecting item of
the list:
* each item should have id property
* to select item from the list, specify id value
Examples:
source = {'obj': {'attr': True}}
value = TraverseHelper.get('/obj/attr', source)
source = {'obj': [
{'id': '1', 'value': 1},
{'id': '2s', 'value': 2},
]}
value = TraverseHelper.get('/obj/2s/value', source)
:param path: string with path to desired value
:param source: python object (list or dict)
:return: object
:raise: ValueError if object is malformed
"""
if path.startswith('/'):
path = path[1:]
queue = deque(path.split('/'))
obj = source
while len(queue):
path = queue.popleft()
if isinstance(obj, types.ListType):
filtered = filter(lambda i: 'id' in i and i['id'] == path, obj)
obj = filtered[0] if filtered else None
elif isinstance(obj, types.DictionaryType):
obj = obj[path] if path else obj
else:
raise ValueError('Object or path is malformed')
return obj
@staticmethod
def update(path, value, source):
"""
Updates value selected with specified path.
Warning: Root object could not be updated
:param path: string with path to desired value
:param value: value
:param source: python object (list or dict)
"""
parent_path = '/'.join(path.split('/')[:-1])
node = TraverseHelper.get(parent_path, source)
key = path[1:].split('/')[-1]
node[key] = value
@staticmethod
def insert(path, value, source):
"""
Inserts new item to selected list.
:param path: string with path to desired value
:param value: value
:param source: python object (list or dict)
"""
node = TraverseHelper.get(path, source)
node.append(value)
def retry(ExceptionToCheck, tries=4, delay=3, backoff=2):
"""Retry calling the decorated function using an exponential backoff.

View File

@ -16,4 +16,4 @@ import uuid
def generate_uuid():
return str(uuid.uuid4()).replace('-', '')
return uuid.uuid4().hex

View File

@ -0,0 +1,13 @@
# Copyright (c) 2013 Mirantis, Inc.
#
# 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.

View File

@ -0,0 +1,70 @@
# Copyright (c) 2013 Mirantis, Inc.
#
# 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.
import unittest
from muranoapi.common.utils import TraverseHelper
class TraverseHelperTests(unittest.TestCase):
def test_simple_root_get(self):
source = {"attr": True}
value = TraverseHelper.get('/', source)
self.assertEqual(value, {"attr": True})
def test_simple_attribute_get(self):
source = {"attr": True}
value = TraverseHelper.get('/attr', source)
self.assertEqual(value, True)
def test_attribute_get(self):
source = {'obj': {'attr': True}}
value = TraverseHelper.get('/obj/attr', source)
self.assertEqual(value, True)
def test_list_item_attribute_get_(self):
source = {'obj': [
{'id': '1', 'value': 1},
{'id': '2s', 'value': 2},
]}
value = TraverseHelper.get('/obj/2s/value', source)
self.assertEqual(value, 2)
def test_simple_attribute_set(self):
source = {"attr": True}
TraverseHelper.update('/newAttr', False, source)
value = TraverseHelper.get('/newAttr', source)
self.assertEqual(value, False)
def test_simple_attribute_update(self):
source = {"attr": True}
TraverseHelper.update('/attr', False, source)
value = TraverseHelper.get('/attr', source)
self.assertEqual(value, False)
def test_attribute_update(self):
source = {"obj": {"attr": True}}
TraverseHelper.update('/obj/attr', False, source)
value = TraverseHelper.get('/obj/attr', source)
self.assertEqual(value, False)
def test_simple_adding_item_to_list(self):
source = {"attr": [1, 2, 3]}
TraverseHelper.insert('/attr', 4, source)
value = TraverseHelper.get('/attr', source)
self.assertEqual(value, [1, 2, 3, 4])
def test_adding_item_to_list(self):
source = {"obj": {"attr": [1, 2, 3]}}
TraverseHelper.insert('/obj/attr', 4, source)
value = TraverseHelper.get('/obj/attr', source)
self.assertEqual(value, [1, 2, 3, 4])