Add custom yaml class
- **duplicate key detection** yaml.load('{"a": 1, "a": 2}') == {'a': 2} error should be raised in case of duplicate keys. - **load mappings as OrderedDict**. this allows to run workloads in the same order as they are in task file. Change-Id: Iea05cd84e55c843e461c92c493ebb1342647ed3b
This commit is contained in:
parent
c3a8c8a573
commit
5d4eade920
52
rally/common/yamlutils.py
Normal file
52
rally/common/yamlutils.py
Normal file
@ -0,0 +1,52 @@
|
||||
# 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 collections
|
||||
|
||||
import yaml
|
||||
from yaml import constructor
|
||||
from yaml import loader
|
||||
from yaml import nodes
|
||||
from yaml import parser
|
||||
from yaml import resolver
|
||||
|
||||
ParserError = parser.ParserError
|
||||
|
||||
|
||||
def _construct_mapping(loader, node, deep=False):
|
||||
keys = []
|
||||
if isinstance(node, nodes.MappingNode):
|
||||
for key_node, value_node in node.value:
|
||||
key = loader.construct_object(key_node, deep=deep)
|
||||
if key in keys:
|
||||
raise constructor.ConstructorError(
|
||||
"while constructing a mapping",
|
||||
node.start_mark,
|
||||
"the key (%s) is redefined" % key,
|
||||
key_node.start_mark)
|
||||
keys.append(key)
|
||||
return collections.OrderedDict(loader.construct_pairs(node))
|
||||
|
||||
|
||||
class _SafeLoader(loader.SafeLoader):
|
||||
pass
|
||||
|
||||
|
||||
def safe_load(stream):
|
||||
"""Load stream to create python object
|
||||
|
||||
:param stream: json/yaml stream.
|
||||
:returns: dict object
|
||||
"""
|
||||
_SafeLoader.add_constructor(resolver.BaseResolver.DEFAULT_MAPPING_TAG,
|
||||
_construct_mapping)
|
||||
return yaml.load(stream, _SafeLoader)
|
40
tests/unit/common/test_yamlutils.py
Normal file
40
tests/unit/common/test_yamlutils.py
Normal file
@ -0,0 +1,40 @@
|
||||
# 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.
|
||||
|
||||
from yaml import constructor
|
||||
|
||||
from rally.common import yamlutils
|
||||
from tests.unit import test
|
||||
|
||||
|
||||
class YamlTestcase(test.TestCase):
|
||||
"""Test yaml loading method."""
|
||||
|
||||
def setUp(self):
|
||||
super(YamlTestcase, self).setUp()
|
||||
|
||||
def test_safe_load(self):
|
||||
stream = "{'a': 1, 'b': {'a': 2}}"
|
||||
stream_obj = yamlutils.safe_load(stream)
|
||||
self.assertEqual({"a": 1, "b": {"a": 2}},
|
||||
stream_obj)
|
||||
|
||||
def test_safe_load_duplicate_key(self):
|
||||
stream = "{'a': 1, 'a': 2}"
|
||||
self.assertRaises(constructor.ConstructorError,
|
||||
yamlutils.safe_load, stream)
|
||||
|
||||
def test_safe_load_order_key(self):
|
||||
stream = "{'b': 1, 'a': 1, 'c': 1}"
|
||||
stream_obj = yamlutils.safe_load(stream)
|
||||
self.assertEqual({"a": 1, "b": 1, "c": 1}, stream_obj)
|
||||
self.assertEqual(["b", "a", "c"], list(stream_obj))
|
Loading…
x
Reference in New Issue
Block a user