From 3db30feebbde2c9e74f27a656931fa0d6bcb6920 Mon Sep 17 00:00:00 2001 From: Edward MacGillivray Date: Fri, 13 Oct 2017 14:01:39 -0700 Subject: Relocate iniparser to yardstick.network_services.helpers Change-Id: I1f457c9c24f2ca84dde61b64f58edaff8952670a Signed-off-by: Edward MacGillivray --- .../network_services/helpers/test_iniparser.py | 225 +++++++++++++++++++ .../vnf_generic/vnf/test_iniparser.py | 225 ------------------- .../vnf_generic/vnf/test_prox_vnf.py | 2 +- yardstick/network_services/helpers/iniparser.py | 249 +++++++++++++++++++++ .../network_services/vnf_generic/vnf/iniparser.py | 249 --------------------- .../vnf_generic/vnf/prox_helpers.py | 11 +- 6 files changed, 480 insertions(+), 481 deletions(-) create mode 100644 tests/unit/network_services/helpers/test_iniparser.py delete mode 100644 tests/unit/network_services/vnf_generic/vnf/test_iniparser.py create mode 100644 yardstick/network_services/helpers/iniparser.py delete mode 100644 yardstick/network_services/vnf_generic/vnf/iniparser.py diff --git a/tests/unit/network_services/helpers/test_iniparser.py b/tests/unit/network_services/helpers/test_iniparser.py new file mode 100644 index 000000000..bd27b497e --- /dev/null +++ b/tests/unit/network_services/helpers/test_iniparser.py @@ -0,0 +1,225 @@ +# Copyright (c) 2017 Intel Corporation +# +# 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 __future__ import absolute_import + +import unittest +from contextlib import contextmanager +import mock + +from tests.unit import STL_MOCKS + + +STLClient = mock.MagicMock() +stl_patch = mock.patch.dict("sys.modules", STL_MOCKS) +stl_patch.start() + +if stl_patch: + from yardstick.network_services.helpers.iniparser import ParseError + from yardstick.network_services.helpers.iniparser import LineParser + from yardstick.network_services.helpers.iniparser import BaseParser + from yardstick.network_services.helpers.iniparser import ConfigParser + +PARSE_TEXT_1 = """\ + +[section1] +key1=value1 +list1: value2 + value3 + value4 +key3='single quote value' ; comment here +key4= + +[section2] ; comment with #2 other symbol +# here is a comment line +list2: value5 +key with no value # mixed comment ; symbols +; another comment line +key5= + +[section1] ; reopen a section! +key2="double quote value" +""" + +PARSE_TEXT_2 = """\ +[section1] +list1 = item1 + item2 + ended by eof""" + +PARSE_TEXT_BAD_1 = """\ +key1=value1 +""" + +PARSE_TEXT_BAD_2 = """\ +[section1 +""" + +PARSE_TEXT_BAD_3 = """\ +[] +""" + +PARSE_TEXT_BAD_4 = """\ +[section1] + bad continuation +""" + +PARSE_TEXT_BAD_5 = """\ +[section1] +=value with no key +""" + + +class TestParseError(unittest.TestCase): + + def test___str__(self): + error = ParseError('a', 2, 'c') + self.assertEqual(str(error), "at line 2, a: 'c'") + + +class TestLineParser(unittest.TestCase): + + def test___repr__(self): + line_parser = LineParser('', 101) + self.assertIsNotNone(repr(line_parser)) + + def test_error_invalid_assignment(self): + line_parser = LineParser('', 101) + self.assertIsNotNone(line_parser.error_invalid_assignment()) + + +class TestBaseParser(unittest.TestCase): + + @staticmethod + def make_open(text_blob): + @contextmanager + def internal_open(*args, **kwargs): + yield text_blob.split('\n') + + return internal_open + + def test_parse(self): + parser = BaseParser() + parser.parse() + + def test_parse_empty_string(self): + parser = BaseParser() + self.assertIsNone(parser.parse('')) + + def test_not_implemented_methods(self): + parser = BaseParser() + + with self.assertRaises(NotImplementedError): + parser.assignment('key', 'value', LineParser('', 100)) + + with self.assertRaises(NotImplementedError): + parser.new_section('section') + + with self.assertRaises(NotImplementedError): + parser.comment('comment') + + +class TestConfigParser(unittest.TestCase): + + @staticmethod + def make_open(text_blob): + @contextmanager + def internal_open(*args, **kwargs): + yield text_blob.split('\n') + + return internal_open + + @mock.patch('yardstick.network_services.helpers.iniparser.open') + def test_parse(self, mock_open): + mock_open.side_effect = self.make_open(PARSE_TEXT_1) + + existing_data = [['section0', [['key0', 'value0']]]] + config_parser = ConfigParser('my_file', existing_data) + config_parser.parse() + + expected = [ + [ + 'section0', + [ + ['key0', 'value0'], + ], + ], + [ + 'section1', + [ + ['key1', 'value1'], + ['list1', 'value2\nvalue3\nvalue4'], + ['key3', 'single quote value'], + ['key4', ''], + ['key2', 'double quote value'], + ], + ], + [ + 'section2', + [ + ['list2', 'value5'], + ['key with no value', '@'], + ['key5', ''], + ], + ], + ] + + self.assertEqual(config_parser.sections, expected) + self.assertIsNotNone(config_parser.find_section('section1')) + self.assertIsNone(config_parser.find_section('section3')) + self.assertEqual(config_parser.find_section_index('section1'), 1) + self.assertEqual(config_parser.find_section_index('section3'), -1) + + @mock.patch('yardstick.network_services.helpers.iniparser.open') + def test_parse_2(self, mock_open): + mock_open.side_effect = self.make_open(PARSE_TEXT_2) + + config_parser = ConfigParser('my_file') + config_parser.parse() + + expected = [ + [ + 'section1', + [ + ['list1', 'item1\nitem2\nended by eof'], + ], + ], + ] + + self.assertEqual(config_parser.sections, expected) + + @mock.patch('yardstick.network_services.helpers.iniparser.open') + def test_parse_negative(self, mock_open): + bad_text_dict = { + 'no section': PARSE_TEXT_BAD_1, + 'incomplete section': PARSE_TEXT_BAD_2, + 'empty section name': PARSE_TEXT_BAD_3, + 'bad_continuation': PARSE_TEXT_BAD_4, + 'value with no key': PARSE_TEXT_BAD_5, + } + + for bad_reason, bad_text in bad_text_dict.items(): + mock_open.side_effect = self.make_open(bad_text) + + config_parser = ConfigParser('my_file', []) + + try: + # TODO: replace with assertRaises, when the UT framework supports + # advanced messages when exceptions fail to occur + config_parser.parse() + except ParseError: + pass + else: + self.fail('\n'.join([bad_reason, bad_text, str(config_parser.sections)])) diff --git a/tests/unit/network_services/vnf_generic/vnf/test_iniparser.py b/tests/unit/network_services/vnf_generic/vnf/test_iniparser.py deleted file mode 100644 index 1ad8df9c6..000000000 --- a/tests/unit/network_services/vnf_generic/vnf/test_iniparser.py +++ /dev/null @@ -1,225 +0,0 @@ -# Copyright (c) 2017 Intel Corporation -# -# 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 __future__ import absolute_import - -import unittest -from contextlib import contextmanager -import mock - -from tests.unit import STL_MOCKS - - -STLClient = mock.MagicMock() -stl_patch = mock.patch.dict("sys.modules", STL_MOCKS) -stl_patch.start() - -if stl_patch: - from yardstick.network_services.vnf_generic.vnf.iniparser import ParseError - from yardstick.network_services.vnf_generic.vnf.iniparser import LineParser - from yardstick.network_services.vnf_generic.vnf.iniparser import BaseParser - from yardstick.network_services.vnf_generic.vnf.iniparser import ConfigParser - -PARSE_TEXT_1 = """\ - -[section1] -key1=value1 -list1: value2 - value3 - value4 -key3='single quote value' ; comment here -key4= - -[section2] ; comment with #2 other symbol -# here is a comment line -list2: value5 -key with no value # mixed comment ; symbols -; another comment line -key5= - -[section1] ; reopen a section! -key2="double quote value" -""" - -PARSE_TEXT_2 = """\ -[section1] -list1 = item1 - item2 - ended by eof""" - -PARSE_TEXT_BAD_1 = """\ -key1=value1 -""" - -PARSE_TEXT_BAD_2 = """\ -[section1 -""" - -PARSE_TEXT_BAD_3 = """\ -[] -""" - -PARSE_TEXT_BAD_4 = """\ -[section1] - bad continuation -""" - -PARSE_TEXT_BAD_5 = """\ -[section1] -=value with no key -""" - - -class TestParseError(unittest.TestCase): - - def test___str__(self): - error = ParseError('a', 2, 'c') - self.assertEqual(str(error), "at line 2, a: 'c'") - - -class TestLineParser(unittest.TestCase): - - def test___repr__(self): - line_parser = LineParser('', 101) - self.assertIsNotNone(repr(line_parser)) - - def test_error_invalid_assignment(self): - line_parser = LineParser('', 101) - self.assertIsNotNone(line_parser.error_invalid_assignment()) - - -class TestBaseParser(unittest.TestCase): - - @staticmethod - def make_open(text_blob): - @contextmanager - def internal_open(*args, **kwargs): - yield text_blob.split('\n') - - return internal_open - - def test_parse(self): - parser = BaseParser() - parser.parse() - - def test_parse_empty_string(self): - parser = BaseParser() - self.assertIsNone(parser.parse('')) - - def test_not_implemented_methods(self): - parser = BaseParser() - - with self.assertRaises(NotImplementedError): - parser.assignment('key', 'value', LineParser('', 100)) - - with self.assertRaises(NotImplementedError): - parser.new_section('section') - - with self.assertRaises(NotImplementedError): - parser.comment('comment') - - -class TestConfigParser(unittest.TestCase): - - @staticmethod - def make_open(text_blob): - @contextmanager - def internal_open(*args, **kwargs): - yield text_blob.split('\n') - - return internal_open - - @mock.patch('yardstick.network_services.vnf_generic.vnf.iniparser.open') - def test_parse(self, mock_open): - mock_open.side_effect = self.make_open(PARSE_TEXT_1) - - existing_data = [['section0', [['key0', 'value0']]]] - config_parser = ConfigParser('my_file', existing_data) - config_parser.parse() - - expected = [ - [ - 'section0', - [ - ['key0', 'value0'], - ], - ], - [ - 'section1', - [ - ['key1', 'value1'], - ['list1', 'value2\nvalue3\nvalue4'], - ['key3', 'single quote value'], - ['key4', ''], - ['key2', 'double quote value'], - ], - ], - [ - 'section2', - [ - ['list2', 'value5'], - ['key with no value', '@'], - ['key5', ''], - ], - ], - ] - - self.assertEqual(config_parser.sections, expected) - self.assertIsNotNone(config_parser.find_section('section1')) - self.assertIsNone(config_parser.find_section('section3')) - self.assertEqual(config_parser.find_section_index('section1'), 1) - self.assertEqual(config_parser.find_section_index('section3'), -1) - - @mock.patch('yardstick.network_services.vnf_generic.vnf.iniparser.open') - def test_parse_2(self, mock_open): - mock_open.side_effect = self.make_open(PARSE_TEXT_2) - - config_parser = ConfigParser('my_file') - config_parser.parse() - - expected = [ - [ - 'section1', - [ - ['list1', 'item1\nitem2\nended by eof'], - ], - ], - ] - - self.assertEqual(config_parser.sections, expected) - - @mock.patch('yardstick.network_services.vnf_generic.vnf.iniparser.open') - def test_parse_negative(self, mock_open): - bad_text_dict = { - 'no section': PARSE_TEXT_BAD_1, - 'incomplete section': PARSE_TEXT_BAD_2, - 'empty section name': PARSE_TEXT_BAD_3, - 'bad_continuation': PARSE_TEXT_BAD_4, - 'value with no key': PARSE_TEXT_BAD_5, - } - - for bad_reason, bad_text in bad_text_dict.items(): - mock_open.side_effect = self.make_open(bad_text) - - config_parser = ConfigParser('my_file', []) - - try: - # TODO: replace with assertRaises, when the UT framework supports - # advanced messages when exceptions fail to occur - config_parser.parse() - except ParseError: - pass - else: - self.fail('\n'.join([bad_reason, bad_text, str(config_parser.sections)])) diff --git a/tests/unit/network_services/vnf_generic/vnf/test_prox_vnf.py b/tests/unit/network_services/vnf_generic/vnf/test_prox_vnf.py index 09060ff57..a6d40877d 100644 --- a/tests/unit/network_services/vnf_generic/vnf/test_prox_vnf.py +++ b/tests/unit/network_services/vnf_generic/vnf/test_prox_vnf.py @@ -376,7 +376,7 @@ class TestProxApproxVnf(unittest.TestCase): return file_path @mock.patch('yardstick.benchmark.scenarios.networking.vnf_generic.open', create=True) - @mock.patch('yardstick.network_services.vnf_generic.vnf.iniparser.open', create=True) + @mock.patch('yardstick.network_services.helpers.iniparser.open', create=True) @mock.patch(SSH_HELPER) def test_run_prox(self, ssh, *_): mock_ssh(ssh) diff --git a/yardstick/network_services/helpers/iniparser.py b/yardstick/network_services/helpers/iniparser.py new file mode 100644 index 000000000..98256e08a --- /dev/null +++ b/yardstick/network_services/helpers/iniparser.py @@ -0,0 +1,249 @@ +# Copyright 2012 OpenStack Foundation +# +# 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 ParseError(Exception): + + def __init__(self, message, line_no, line): + self.msg = message + self.line = line + self.line_no = line_no + + def __str__(self): + return 'at line %d, %s: %r' % (self.line_no, self.msg, self.line) + + +class SectionParseError(ParseError): + + pass + + +class LineParser(object): + + PARSE_EXC = ParseError + + @staticmethod + def strip_key_value(key, value): + key = key.strip() + value = value.strip() + if value and value[0] == value[-1] and value.startswith(('"', "'")): + value = value[1:-1] + return key, [value] + + def __init__(self, line, line_no): + super(LineParser, self).__init__() + self.line = line + self.line_no = line_no + self.continuation = line != line.lstrip() + semi_active, _, semi_comment = line.partition(';') + pound_active, _, pound_comment = line.partition('#') + if not semi_comment and not pound_comment: + self.active = line.strip() + self.comment = '' + elif len(semi_comment) > len(pound_comment): + self.active = semi_active.strip() + self.comment = semi_comment.strip() + else: + self.active = pound_active.strip() + self.comment = pound_comment.strip() + self._section_name = None + + def __repr__(self): + template = "line %d: active '%s' comment '%s'\n%s" + return template % (self.line_no, self.active, self.comment, self.line) + + @property + def section_name(self): + if self._section_name is None: + if not self.active.startswith('['): + raise self.error_no_section_start_bracket() + if not self.active.endswith(']'): + raise self.error_no_section_end_bracket() + self._section_name = '' + if self.active: + self._section_name = self.active[1:-1] + if not self._section_name: + raise self.error_no_section_name() + return self._section_name + + def is_active_line(self): + return bool(self.active) + + def is_continuation(self): + return self.continuation + + def split_key_value(self): + for sep in ['=', ':']: + words = self.active.split(sep, 1) + try: + return self.strip_key_value(*words) + except TypeError: + pass + + return self.active.rstrip(), '@' + + def error_invalid_assignment(self): + return self.PARSE_EXC("No ':' or '=' found in assignment", self.line_no, self.line) + + def error_empty_key(self): + return self.PARSE_EXC('Key cannot be empty', self.line_no, self.line) + + def error_unexpected_continuation(self): + return self.PARSE_EXC('Unexpected continuation line', self.line_no, self.line) + + def error_no_section_start_bracket(self): + return SectionParseError('Invalid section (must start with [)', self.line_no, self.line) + + def error_no_section_end_bracket(self): + return self.PARSE_EXC('Invalid section (must end with ])', self.line_no, self.line) + + def error_no_section_name(self): + return self.PARSE_EXC('Empty section name', self.line_no, self.line) + + +class BaseParser(object): + + def parse(self, data=None): + if data is not None: + return self._parse(data.splitlines()) + + def _next_key_value(self, line_parser, key, value): + self.comment(line_parser) + + if not line_parser.is_active_line(): + # Blank line, ends multi-line values + if key: + key, value = self.assignment(key, value, line_parser) + return key, value + + if line_parser.is_continuation(): + # Continuation of previous assignment + if key is None: + raise line_parser.error_unexpected_continuation() + + value.append(line_parser.active.lstrip()) + return key, value + + if key: + # Flush previous assignment, if any + key, value = self.assignment(key, value, line_parser) + + try: + # Section start + self.new_section(line_parser) + except SectionParseError: + pass + else: + return key, value + + key, value = line_parser.split_key_value() + if not key: + raise line_parser.error_empty_key() + return key, value + + def _parse(self, line_iter): + key = None + value = [] + + parse_iter = (LineParser(line, line_no) for line_no, line in enumerate(line_iter)) + for line_parser in parse_iter: + key, value = self._next_key_value(line_parser, key, value) + + if key: + # Flush previous assignment, if any + self.assignment(key, value, LineParser('EOF', -1)) + + def _assignment(self, key, value, line_parser): + """Called when a full assignment is parsed.""" + raise NotImplementedError() + + def assignment(self, key, value, line_parser): + self._assignment(key, value, line_parser) + return None, [] + + def new_section(self, line_parser): + """Called when a new section is started.""" + raise NotImplementedError() + + def comment(self, line_parser): + """Called when a comment is parsed.""" + raise NotImplementedError() + + +class ConfigParser(BaseParser): + """Parses a single config file, populating 'sections' to look like: + + [ + [ + 'section1', + [ + ['key1', 'value1\nvalue2'], + ['key2', 'value3\nvalue4'], + ], + ], + [ + 'section2', + [ + ['key3', 'value5\nvalue6'], + ], + ], + ] + """ + + def __init__(self, filename, sections=None): + super(ConfigParser, self).__init__() + self.filename = filename + if sections is not None: + self.sections = sections + else: + self.sections = [] + self.section_name = None + self.section = None + + def parse(self, data=None): + if not data: + data = self.filename + with open(data) as f: + return self._parse(f) + + def __iter__(self): + return iter(self.sections) + + def find_section_index(self, section_name): + return next((i for i, (name, value) in enumerate(self) if name == section_name), -1) + + def find_section(self, section_name): + return next((value for name, value in self.sections if name == section_name), None) + + def new_section(self, line_parser): + section_name = line_parser.section_name + index = self.find_section_index(section_name) + self.section_name = section_name + if index == -1: + self.section = [section_name, []] + self.sections.append(self.section) + else: + self.section = self.sections[index] + + def _assignment(self, key, value, line_parser): + if not self.section_name: + raise line_parser.error_no_section_name() + + value = '\n'.join(value) + entry = [key, value] + self.section[1].append(entry) + + def comment(self, line_parser): + """Called when a comment is parsed.""" + pass diff --git a/yardstick/network_services/vnf_generic/vnf/iniparser.py b/yardstick/network_services/vnf_generic/vnf/iniparser.py deleted file mode 100644 index 98256e08a..000000000 --- a/yardstick/network_services/vnf_generic/vnf/iniparser.py +++ /dev/null @@ -1,249 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# -# 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 ParseError(Exception): - - def __init__(self, message, line_no, line): - self.msg = message - self.line = line - self.line_no = line_no - - def __str__(self): - return 'at line %d, %s: %r' % (self.line_no, self.msg, self.line) - - -class SectionParseError(ParseError): - - pass - - -class LineParser(object): - - PARSE_EXC = ParseError - - @staticmethod - def strip_key_value(key, value): - key = key.strip() - value = value.strip() - if value and value[0] == value[-1] and value.startswith(('"', "'")): - value = value[1:-1] - return key, [value] - - def __init__(self, line, line_no): - super(LineParser, self).__init__() - self.line = line - self.line_no = line_no - self.continuation = line != line.lstrip() - semi_active, _, semi_comment = line.partition(';') - pound_active, _, pound_comment = line.partition('#') - if not semi_comment and not pound_comment: - self.active = line.strip() - self.comment = '' - elif len(semi_comment) > len(pound_comment): - self.active = semi_active.strip() - self.comment = semi_comment.strip() - else: - self.active = pound_active.strip() - self.comment = pound_comment.strip() - self._section_name = None - - def __repr__(self): - template = "line %d: active '%s' comment '%s'\n%s" - return template % (self.line_no, self.active, self.comment, self.line) - - @property - def section_name(self): - if self._section_name is None: - if not self.active.startswith('['): - raise self.error_no_section_start_bracket() - if not self.active.endswith(']'): - raise self.error_no_section_end_bracket() - self._section_name = '' - if self.active: - self._section_name = self.active[1:-1] - if not self._section_name: - raise self.error_no_section_name() - return self._section_name - - def is_active_line(self): - return bool(self.active) - - def is_continuation(self): - return self.continuation - - def split_key_value(self): - for sep in ['=', ':']: - words = self.active.split(sep, 1) - try: - return self.strip_key_value(*words) - except TypeError: - pass - - return self.active.rstrip(), '@' - - def error_invalid_assignment(self): - return self.PARSE_EXC("No ':' or '=' found in assignment", self.line_no, self.line) - - def error_empty_key(self): - return self.PARSE_EXC('Key cannot be empty', self.line_no, self.line) - - def error_unexpected_continuation(self): - return self.PARSE_EXC('Unexpected continuation line', self.line_no, self.line) - - def error_no_section_start_bracket(self): - return SectionParseError('Invalid section (must start with [)', self.line_no, self.line) - - def error_no_section_end_bracket(self): - return self.PARSE_EXC('Invalid section (must end with ])', self.line_no, self.line) - - def error_no_section_name(self): - return self.PARSE_EXC('Empty section name', self.line_no, self.line) - - -class BaseParser(object): - - def parse(self, data=None): - if data is not None: - return self._parse(data.splitlines()) - - def _next_key_value(self, line_parser, key, value): - self.comment(line_parser) - - if not line_parser.is_active_line(): - # Blank line, ends multi-line values - if key: - key, value = self.assignment(key, value, line_parser) - return key, value - - if line_parser.is_continuation(): - # Continuation of previous assignment - if key is None: - raise line_parser.error_unexpected_continuation() - - value.append(line_parser.active.lstrip()) - return key, value - - if key: - # Flush previous assignment, if any - key, value = self.assignment(key, value, line_parser) - - try: - # Section start - self.new_section(line_parser) - except SectionParseError: - pass - else: - return key, value - - key, value = line_parser.split_key_value() - if not key: - raise line_parser.error_empty_key() - return key, value - - def _parse(self, line_iter): - key = None - value = [] - - parse_iter = (LineParser(line, line_no) for line_no, line in enumerate(line_iter)) - for line_parser in parse_iter: - key, value = self._next_key_value(line_parser, key, value) - - if key: - # Flush previous assignment, if any - self.assignment(key, value, LineParser('EOF', -1)) - - def _assignment(self, key, value, line_parser): - """Called when a full assignment is parsed.""" - raise NotImplementedError() - - def assignment(self, key, value, line_parser): - self._assignment(key, value, line_parser) - return None, [] - - def new_section(self, line_parser): - """Called when a new section is started.""" - raise NotImplementedError() - - def comment(self, line_parser): - """Called when a comment is parsed.""" - raise NotImplementedError() - - -class ConfigParser(BaseParser): - """Parses a single config file, populating 'sections' to look like: - - [ - [ - 'section1', - [ - ['key1', 'value1\nvalue2'], - ['key2', 'value3\nvalue4'], - ], - ], - [ - 'section2', - [ - ['key3', 'value5\nvalue6'], - ], - ], - ] - """ - - def __init__(self, filename, sections=None): - super(ConfigParser, self).__init__() - self.filename = filename - if sections is not None: - self.sections = sections - else: - self.sections = [] - self.section_name = None - self.section = None - - def parse(self, data=None): - if not data: - data = self.filename - with open(data) as f: - return self._parse(f) - - def __iter__(self): - return iter(self.sections) - - def find_section_index(self, section_name): - return next((i for i, (name, value) in enumerate(self) if name == section_name), -1) - - def find_section(self, section_name): - return next((value for name, value in self.sections if name == section_name), None) - - def new_section(self, line_parser): - section_name = line_parser.section_name - index = self.find_section_index(section_name) - self.section_name = section_name - if index == -1: - self.section = [section_name, []] - self.sections.append(self.section) - else: - self.section = self.sections[index] - - def _assignment(self, key, value, line_parser): - if not self.section_name: - raise line_parser.error_no_section_name() - - value = '\n'.join(value) - entry = [key, value] - self.section[1].append(entry) - - def comment(self, line_parser): - """Called when a comment is parsed.""" - pass diff --git a/yardstick/network_services/vnf_generic/vnf/prox_helpers.py b/yardstick/network_services/vnf_generic/vnf/prox_helpers.py index 992b6d06e..ac5abfbcb 100644 --- a/yardstick/network_services/vnf_generic/vnf/prox_helpers.py +++ b/yardstick/network_services/vnf_generic/vnf/prox_helpers.py @@ -14,28 +14,27 @@ from __future__ import absolute_import import array -import operator -import logging import io +import logging +import operator import os import re import select import socket - -from collections import OrderedDict, namedtuple import time +from collections import OrderedDict, namedtuple from contextlib import contextmanager from itertools import repeat, chain from multiprocessing import Queue import six -from six.moves import zip, StringIO from six.moves import cStringIO +from six.moves import zip, StringIO from yardstick.benchmark.scenarios.networking.vnf_generic import find_relative_file from yardstick.common import utils from yardstick.common.utils import SocketTopology, join_non_strings, try_int -from yardstick.network_services.vnf_generic.vnf.iniparser import ConfigParser +from yardstick.network_services.helpers.iniparser import ConfigParser from yardstick.network_services.vnf_generic.vnf.sample_vnf import ClientResourceHelper from yardstick.network_services.vnf_generic.vnf.sample_vnf import DpdkVnfSetupEnvHelper -- cgit 1.2.3-korg