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:
chenhb-zte 2017-01-23 15:53:50 +08:00
parent c3a8c8a573
commit 5d4eade920
2 changed files with 92 additions and 0 deletions

52
rally/common/yamlutils.py Normal file
View 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)

View 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))