From 3a9d653b098650eff2c9e34ec170c434a42ce1c3 Mon Sep 17 00:00:00 2001 From: Ben Nemec Date: Tue, 20 Mar 2018 16:34:06 +0000 Subject: [PATCH] Remove MultiConfigParser This has been deprecated for quite a while and some of the upcoming work to be done in oslo.config will be easier if we don't have to deal with this unused parser too. The class is still currently in use in networking-cisco, but in change https://review.openstack.org/554617 we have provided a fix that removes their reliance on it. They are planning to remove it entirely in Rocky and are only testing against a capped version in Queens so we are not going to wait on them. Change-Id: Id6ae40311f967e172e45bcb0e61812365a72618b --- doc/source/reference/parser.rst | 3 - oslo_config/cfg.py | 112 -------------------------------- oslo_config/tests/test_cfg.py | 92 ++------------------------ 3 files changed, 7 insertions(+), 200 deletions(-) diff --git a/doc/source/reference/parser.rst b/doc/source/reference/parser.rst index 64b8b384..2d9430f0 100644 --- a/doc/source/reference/parser.rst +++ b/doc/source/reference/parser.rst @@ -6,6 +6,3 @@ File Parsing .. autoclass:: oslo_config.cfg.ConfigParser :members: parse - -.. autoclass:: oslo_config.cfg.MultiConfigParser - :members: read, get diff --git a/oslo_config/cfg.py b/oslo_config/cfg.py index 1fc30785..6ce07331 100644 --- a/oslo_config/cfg.py +++ b/oslo_config/cfg.py @@ -496,11 +496,9 @@ import os import string import sys -from debtcollector import removals import enum import six - from oslo_config import iniparser from oslo_config import types @@ -2009,116 +2007,6 @@ class ConfigParser(iniparser.BaseParser): config_file, sections, normalized) -@removals.remove(version='3.4', removal_version='4.0') -class MultiConfigParser(object): - """A ConfigParser which handles multi-opts. - - All methods in this class which accept config names should treat a section - name of None as 'DEFAULT'. - - This class was deprecated in Mitaka and should be removed in Ocata. - _Namespace holds values, ConfigParser._parse_file reads one file into a - _Namespace and ConfigOpts._parse_config_files reads multiple files into a - _Namespace. - """ - - _deprecated_opt_message = ('Option "%(dep_option)s" from group ' - '"%(dep_group)s" is deprecated. Use option ' - '"%(option)s" from group "%(group)s".') - - def __init__(self): - self.parsed = [] - self._normalized = [] - self._emitted_deprecations = set() - - def read(self, config_files): - read_ok = [] - - for filename in config_files: - sections = {} - normalized = {} - parser = ConfigParser(filename, sections) - parser._add_normalized(normalized) - - try: - parser.parse() - except IOError: - continue - self._add_parsed_config_file(filename, sections, normalized) - read_ok.append(filename) - - return read_ok - - def _add_parsed_config_file(self, filename, sections, normalized): - """Add a parsed config file to the list of parsed files. - - :param sections: a mapping of section name to dicts of config values - :param normalized: sections mapping with section names normalized - :raises: ConfigFileValueError - """ - self.parsed.insert(0, sections) - self._normalized.insert(0, normalized) - - def get(self, names, multi=False): - return self._get(names, multi=multi) - - def _get(self, names, multi=False, normalized=False, current_name=None): - """Fetch a config file value from the parsed files. - - :param names: a list of (section, name) tuples - :param multi: a boolean indicating whether to return multiple values - :param normalized: whether to normalize group names to lowercase - :param current_name: current name in tuple being checked - """ - rvalue = [] - - def normalize(name): - if name is None: - name = 'DEFAULT' - return _normalize_group_name(name) if normalized else name - - names = [(normalize(section), name) for section, name in names] - - for sections in (self._normalized if normalized else self.parsed): - for section, name in names: - if section not in sections: - continue - if name in sections[section]: - current_name = current_name or names[0] - self._check_deprecated((section, name), current_name, - names[1:]) - val = sections[section][name] - if multi: - rvalue = val + rvalue - else: - return val - if multi and rvalue != []: - return rvalue - raise KeyError - - def _check_deprecated(self, name, current, deprecated): - """Check for usage of deprecated names. - - :param name: A tuple of the form (group, name) representing the group - and name where an opt value was found. - :param current: A tuple of the form (group, name) representing the - current name for an option. - :param deprecated: A list of tuples with the same format as the name - param which represent any deprecated names for an option. - If the name param matches any entries in this list a - deprecation warning will be logged. - """ - if name in deprecated and name not in self._emitted_deprecations: - self._emitted_deprecations.add(name) - current = (current[0] or 'DEFAULT', current[1]) - # NOTE(bnemec): Not using versionutils for this to avoid a - # circular dependency between oslo.config and whatever library - # versionutils ends up in. - LOG.warning(self._deprecated_opt_message, - {'dep_option': name[1], 'dep_group': name[0], - 'option': current[1], 'group': current[0]}) - - class _Namespace(argparse.Namespace): """An argparse namespace which also stores config file values. diff --git a/oslo_config/tests/test_cfg.py b/oslo_config/tests/test_cfg.py index b1424ac1..22483a58 100644 --- a/oslo_config/tests/test_cfg.py +++ b/oslo_config/tests/test_cfg.py @@ -3964,84 +3964,6 @@ class ConfigParserTestCase(BaseTestCase): namespace) -class MultiConfigParserTestCase(BaseTestCase): - - def test_parse_single_file(self): - paths = self.create_tempfiles([('test', - '[DEFAULT]\n' - 'foo = bar\n' - '[BLAA]\n' - 'bar = foo\n')]) - - parser = cfg.MultiConfigParser() - read_ok = parser.read(paths) - - self.assertEqual(read_ok, paths) - - self.assertIn('DEFAULT', parser.parsed[0]) - self.assertEqual(parser.parsed[0]['DEFAULT']['foo'], ['bar']) - self.assertEqual(parser.get([('DEFAULT', 'foo')]), ['bar']) - self.assertEqual(parser.get([('DEFAULT', 'foo')], multi=True), - ['bar']) - self.assertEqual(parser.get([('DEFAULT', 'foo')], multi=True), - ['bar']) - self.assertEqual(parser.get([(None, 'foo')], multi=True), - ['bar']) - self.assertEqual(parser._get([('DEFAULT', 'foo')], - multi=True, normalized=True), - ['bar']) - - self.assertIn('BLAA', parser.parsed[0]) - self.assertEqual(parser.parsed[0]['BLAA']['bar'], ['foo']) - self.assertEqual(parser.get([('BLAA', 'bar')]), ['foo']) - self.assertEqual(parser.get([('BLAA', 'bar')], multi=True), - ['foo']) - self.assertEqual(parser._get([('blaa', 'bar')], - multi=True, normalized=True), - ['foo']) - - def test_parse_multiple_files(self): - paths = self.create_tempfiles([('test1', - '[DEFAULT]\n' - 'foo = bar\n' - '[BLAA]\n' - 'bar = foo'), - ('test2', - '[DEFAULT]\n' - 'foo = barbar\n' - '[BLAA]\n' - 'bar = foofoo\n' - '[bLAa]\n' - 'bar = foofoofoo\n')]) - - parser = cfg.MultiConfigParser() - read_ok = parser.read(paths) - - self.assertEqual(read_ok, paths) - - self.assertIn('DEFAULT', parser.parsed[0]) - self.assertEqual(parser.parsed[0]['DEFAULT']['foo'], ['barbar']) - self.assertIn('DEFAULT', parser.parsed[1]) - self.assertEqual(parser.parsed[1]['DEFAULT']['foo'], ['bar']) - self.assertEqual(parser.get([('DEFAULT', 'foo')]), ['barbar']) - self.assertEqual(parser.get([('DEFAULT', 'foo')], multi=True), - ['bar', 'barbar']) - - self.assertIn('BLAA', parser.parsed[0]) - self.assertIn('bLAa', parser.parsed[0]) - self.assertEqual(parser.parsed[0]['BLAA']['bar'], ['foofoo']) - self.assertEqual(parser.parsed[0]['bLAa']['bar'], ['foofoofoo']) - self.assertIn('BLAA', parser.parsed[1]) - self.assertEqual(parser.parsed[1]['BLAA']['bar'], ['foo']) - self.assertEqual(parser.get([('BLAA', 'bar')]), ['foofoo']) - self.assertEqual(parser.get([('bLAa', 'bar')]), ['foofoofoo']) - self.assertEqual(parser.get([('BLAA', 'bar')], multi=True), - ['foo', 'foofoo']) - self.assertEqual(parser._get([('BLAA', 'bar')], - multi=True, normalized=True), - ['foo', 'foofoo', 'foofoofoo']) - - class NamespaceTestCase(BaseTestCase): def setUp(self): super(NamespaceTestCase, self).setUp() @@ -4909,7 +4831,7 @@ class DeprecationWarningTestBase(BaseTestCase): def setUp(self): super(DeprecationWarningTestBase, self).setUp() self.log_fixture = self.useFixture(fixtures.FakeLogger()) - self._parser_class = cfg.MultiConfigParser + self._parser_class = cfg.ConfigParser class DeprecationWarningTestScenarios(DeprecationWarningTestBase): @@ -4945,7 +4867,7 @@ class DeprecationWarningTestScenarios(DeprecationWarningTestBase): self.assertEqual('baz', self.conf.other.foo) self.assertEqual('baz', self.conf.other.foo) if self.deprecated: - expected = (self._parser_class._deprecated_opt_message % + expected = (cfg._Namespace._deprecated_opt_message % {'dep_option': 'bar', 'dep_group': self.group, 'option': 'foo', @@ -4979,15 +4901,15 @@ class DeprecationWarningTests(DeprecationWarningTestBase): self.log_fixture.output) def test_check_deprecated(self): - parser = self._parser_class() + namespace = cfg._Namespace(None) deprecated_list = [('DEFAULT', 'bar')] - parser._check_deprecated(('DEFAULT', 'bar'), (None, 'foo'), - deprecated_list) + namespace._check_deprecated(('DEFAULT', 'bar'), (None, 'foo'), + deprecated_list) self.assert_message_logged('bar', 'DEFAULT', 'foo', 'DEFAULT') def assert_message_logged(self, deprecated_name, deprecated_group, current_name, current_group): - expected = (self._parser_class._deprecated_opt_message % + expected = (cfg._Namespace._deprecated_opt_message % {'dep_option': deprecated_name, 'dep_group': deprecated_group, 'option': current_name, @@ -5048,7 +4970,7 @@ class DeprecationWarningTests(DeprecationWarningTestBase): self.conf(['--config-file', paths[0]]) self.assertEqual('baz', self.conf.other.foo) - expected = (self._parser_class._deprecated_opt_message % + expected = (cfg._Namespace._deprecated_opt_message % {'dep_option': 'bar', 'dep_group': 'other', 'option': 'foo-bar',