Added Traverse Helper
Added Traverse Helper and unit-tests Simplified generate UUID function Change-Id: I307fc689e592b94e4e084d0e6a164e11c5ec4429
This commit is contained in:
parent
5a57f15ded
commit
0790add5aa
|
@ -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.
|
||||
|
||||
|
|
|
@ -16,4 +16,4 @@ import uuid
|
|||
|
||||
|
||||
def generate_uuid():
|
||||
return str(uuid.uuid4()).replace('-', '')
|
||||
return uuid.uuid4().hex
|
||||
|
|
|
@ -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.
|
|
@ -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])
|
Loading…
Reference in New Issue