Remove ConfigFilter

Per the deprecation in change I04baae695a7ba0bb93c91ea642c4e33c04bf87bd
this can be removed.

Change-Id: I31156e2f47b0d68ea32726cde7f0c2b133022c9f
This commit is contained in:
Ben Nemec 2019-06-17 17:49:44 +00:00 committed by Stephen Finucane
parent 6f5a925c3a
commit c7ac122554
2 changed files with 0 additions and 752 deletions

View File

@ -1,390 +0,0 @@
# Copyright 2014 Red Hat, 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.
r"""
DEPRECATED: This module is deprecated and scheduled for removal in the
U cycle.
There are three use cases for the ConfigFilter class:
1. Help enforce that a given module does not access options registered
by another module, without first declaring those cross-module
dependencies using import_opt().
2. Prevent private configuration opts from being visible to modules
other than the one which registered it.
3. Limit the options on a Cfg object that can be accessed.
.. versionadded:: 1.4
Cross-Module Option Dependencies
--------------------------------
When using the global cfg.CONF object, it is quite common for a module
to require the existence of configuration options registered by other
modules.
For example, if module 'foo' registers the 'blaa' option and the module
'bar' uses the 'blaa' option then 'bar' might do::
import foo
print(CONF.blaa)
However, it's completely non-obvious why foo is being imported (is it
unused, can we remove the import) and where the 'blaa' option comes from.
The CONF.import_opt() method allows such a dependency to be explicitly
declared::
CONF.import_opt('blaa', 'foo')
print(CONF.blaa)
However, import_opt() has a weakness - if 'bar' imports 'foo' using the
import builtin and doesn't use import_opt() to import 'blaa', then 'blaa'
can still be used without problems. Similarly, where multiple options
are registered a module imported via import_opt(), a lazy programmer can
get away with only declaring a dependency on a single option.
The ConfigFilter class provides a way to ensure that options are not
available unless they have been registered in the module or imported using
import_opt() for example with::
CONF = ConfigFilter(cfg.CONF)
CONF.import_opt('blaa', 'foo')
print(CONF.blaa)
no other options other than 'blaa' are available via CONF.
Private Configuration Options
-----------------------------
Libraries which register configuration options typically do not want
users of the library API to access those configuration options. If
API users do access private configuration options, those users will
be disrupted if and when a configuration option is renamed. In other
words, one does not typically wish for the name of the private config
options to be part of the public API.
The ConfigFilter class provides a way for a library to register
options such that they are not visible via the ConfigOpts instance
which the API user supplies to the library. For example::
from __future__ import print_function
from oslo_config.cfg import *
from oslo_config.cfgfilter import *
class Widget(object):
def __init__(self, conf):
self.conf = conf
self._private_conf = ConfigFilter(self.conf)
self._private_conf.register_opt(StrOpt('foo'))
@property
def foo(self):
return self._private_conf.foo
conf = ConfigOpts()
widget = Widget(conf)
print(widget.foo)
print(conf.foo) # raises NoSuchOptError
Limited Configuration Options
-----------------------------
It may be required that when passing a CONF object to other functions we want
to filter that the receiving code is only able to access a restricted subset
of the options that are available on the CONF object. This is essentially a
more general case of the Private Configuration Options and Cross-Module Options
whereby we expose an option that is already present on the underlying CONF
object without providing any means to load it if not present.
So given a CONF object with options defined::
CONF.register_opt(StrOpt('foo'))
CONF.register_opt(StrOpt('bar'))
we can expose options such that only those options are present::
restricted_conf = CfgFilter(CONF)
restricted_conf.expose_opt('foo')
print(restricted_conf.foo)
print(restricted_conf.bar) # raises NoSuchOptError
"""
import collections
import itertools
from debtcollector import removals
from oslo_config import cfg
@removals.removed_class('CliOptRegisteredError')
class CliOptRegisteredError(cfg.Error):
"""Raised when registering cli opt not in original ConfigOpts.
.. versionadded:: 1.12
"""
def __str__(self):
ret = "Cannot register a cli option that was not present in the" \
" original ConfigOpts."
if self.msg:
ret += ": " + self.msg
return ret
@removals.removed_class('ConfigFilter')
class ConfigFilter(collections.Mapping):
"""A helper class which wraps a ConfigOpts object.
ConfigFilter enforces the explicit declaration of dependencies on external
options and allows private options which are not registered with the
wrapped Configopts object.
"""
def __init__(self, conf):
"""Construct a ConfigFilter object.
:param conf: a ConfigOpts object
"""
self._conf = conf
self._fconf = cfg.ConfigOpts()
self._sync()
self._imported_opts = set()
self._imported_groups = dict()
def _sync(self):
if self._fconf._namespace is not self._conf._namespace:
self._fconf.clear()
self._fconf._namespace = self._conf._namespace
self._fconf._args = self._conf._args
def __getattr__(self, name):
"""Look up an option value.
:param name: the opt name (or 'dest', more precisely)
:returns: the option value (after string subsititution) or a GroupAttr
:raises: NoSuchOptError,ConfigFileValueError,TemplateSubstitutionError
"""
if name in self._imported_groups:
return self._imported_groups[name]
elif name in self._imported_opts:
return getattr(self._conf, name)
else:
self._sync()
return getattr(self._fconf, name)
def __getitem__(self, key):
"""Look up an option value."""
return getattr(self, key)
def __contains__(self, key):
"""Return True if key is the name of a registered opt or group."""
return (key in self._fconf or
key in self._imported_opts or
key in self._imported_groups)
def __iter__(self):
"""Iterate over all registered opt and group names."""
return itertools.chain(self._fconf.keys(),
self._imported_opts,
self._imported_groups.keys())
def __len__(self):
"""Return the number of options and option groups."""
return (len(self._fconf) +
len(self._imported_opts) +
len(self._imported_groups))
@staticmethod
def _already_registered(conf, opt, group=None):
group_name = group.name if isinstance(group, cfg.OptGroup) else group
return ((group_name is None and
opt.dest in conf) or
(group_name is not None and
group_name in conf and
opt.dest in conf[group_name]))
def register_opt(self, opt, group=None):
"""Register an option schema.
:param opt: an instance of an Opt sub-class
:param group: an optional OptGroup object or group name
:return: False if the opt was already registered, True otherwise
:raises: DuplicateOptError
"""
if self._already_registered(self._conf, opt, group):
# Raises DuplicateError if there is another opt with the same name
ret = self._conf.register_opt(opt, group)
self._import_opt(opt.dest, group)
return ret
else:
return self._fconf.register_opt(opt, group)
def register_opts(self, opts, group=None):
"""Register multiple option schemas at once."""
for opt in opts:
self.register_opt(opt, group)
def register_cli_opt(self, opt, group=None):
"""Register a CLI option schema.
:param opt: an instance of an Opt sub-class
:param group: an optional OptGroup object or group name
:return: False if the opt was already register, True otherwise
:raises: DuplicateOptError, ArgsAlreadyParsedError
"""
if self._already_registered(self._conf, opt, group):
# Raises DuplicateError if there is another opt with the same name
ret = self._conf.register_opt(
opt, group, cli=True, clear_cache=False)
self._import_opt(opt.dest, group)
return ret
else:
raise CliOptRegisteredError(
"Opt '{0}' cannot be registered.".format(opt.dest))
def register_cli_opts(self, opts, group=None):
"""Register multiple CLI option schemas at once."""
for opt in opts:
self.register_cli_opt(opt, group)
def register_group(self, group):
"""Register an option group.
:param group: an OptGroup object
"""
self._fconf.register_group(group)
def import_opt(self, opt_name, module_str, group=None):
"""Import an option definition from a module.
:param name: the name/dest of the opt
:param module_str: the name of a module to import
:param group: an option OptGroup object or group name
:raises: NoSuchOptError, NoSuchGroupError
"""
self._conf.import_opt(opt_name, module_str, group)
self._import_opt(opt_name, group)
def import_group(self, group, module_str):
"""Import an option group from a module.
Note that this allows access to all options registered with
the group whether or not those options were registered by
the given module.
:param group: an option OptGroup object or group name
:param module_str: the name of a module to import
:raises: ImportError, NoSuchGroupError
"""
self._conf.import_group(group, module_str)
group = self._import_group(group)
group._all_opts = True
def _import_opt(self, opt_name, group):
if group is None:
self._imported_opts.add(opt_name)
return True
else:
group = self._import_group(group)
return group._import_opt(opt_name)
def _import_group(self, group_or_name):
if isinstance(group_or_name, cfg.OptGroup):
group_name = group_or_name.name
else:
group_name = group_or_name
if group_name in self._imported_groups:
return self._imported_groups[group_name]
else:
group = self.GroupAttr(self._conf, group_name)
self._imported_groups[group_name] = group
return group
def expose_opt(self, opt_name, group=None):
"""Expose an option from the underlying conf object.
This allows an object that has already been imported or used from the
base conf object to be seen from the filter object.
:param opt_name: the name/dest of the opt
:param group: an option OptGroup object or group name
"""
self._import_opt(opt_name, group)
def expose_group(self, group):
"""Expose all option from a group in the underlying conf object.
This allows an object that has already been imported or used from the
base conf object to be seen from the filter object.
:param group: an option OptGroup object or group name
"""
group = self._import_group(group)
group._all_opts = True
class GroupAttr(collections.Mapping):
"""Helper class to wrap a group object.
Represents the option values of a group as a mapping and attributes.
"""
def __init__(self, conf, group):
"""Construct a GroupAttr object.
:param conf: a ConfigOpts object
:param group: an OptGroup object
"""
self._conf = conf
self._group = group
self._imported_opts = set()
self._all_opts = False
def __getattr__(self, name):
"""Look up an option value."""
if not self._all_opts and name not in self._imported_opts:
raise cfg.NoSuchOptError(name)
return getattr(self._conf[self._group], name)
def __getitem__(self, key):
"""Look up an option value."""
return getattr(self, key)
def __contains__(self, key):
"""Return True if key is the name of a registered opt or group."""
return key in self._imported_opts
def __iter__(self):
"""Iterate over all registered opt and group names."""
for key in self._imported_opts:
yield key
def __len__(self):
"""Return the number of options and option groups."""
return len(self._imported_opts)
def _import_opt(self, opt_name):
self._imported_opts.add(opt_name)

View File

@ -1,362 +0,0 @@
# Copyright 2014 Red Hat, 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.
from oslotest import base as test_base
import testtools
from oslo_config import cfg
from oslo_config import cfgfilter
class BaseTestCase(test_base.BaseTestCase):
def setUp(self, conf=None):
super(BaseTestCase, self).setUp()
if conf is None:
self.conf = cfg.ConfigOpts()
else:
self.conf = conf
self.fconf = cfgfilter.ConfigFilter(self.conf)
class RegisterTestCase(BaseTestCase):
def test_register_opt_default(self):
self.fconf.register_opt(cfg.StrOpt('foo', default='bar'))
self.assertEqual('bar', self.fconf.foo)
self.assertEqual('bar', self.fconf['foo'])
self.assertIn('foo', self.fconf)
self.assertEqual(set(['config_source', 'foo']), set(self.fconf))
self.assertEqual(2, len(self.fconf))
self.assertNotIn('foo', self.conf)
self.assertEqual(1, len(self.conf))
self.assertRaises(cfg.NoSuchOptError, getattr, self.conf, 'foo')
def test_register_opt_none_default(self):
self.fconf.register_opt(cfg.StrOpt('foo'))
self.assertIsNone(self.fconf.foo)
self.assertIsNone(self.fconf['foo'])
self.assertIn('foo', self.fconf)
self.assertEqual(set(['config_source', 'foo']), set(self.fconf))
self.assertEqual(2, len(self.fconf))
self.assertNotIn('foo', self.conf)
self.assertEqual(1, len(self.conf))
self.assertRaises(cfg.NoSuchOptError, getattr, self.conf, 'foo')
def test_register_grouped_opt_default(self):
self.fconf.register_opt(cfg.StrOpt('foo', default='bar'),
group='blaa')
self.assertEqual('bar', self.fconf.blaa.foo)
self.assertEqual('bar', self.fconf['blaa']['foo'])
self.assertIn('blaa', self.fconf)
self.assertIn('foo', self.fconf.blaa)
self.assertEqual(set(['config_source', 'blaa']), set(self.fconf))
self.assertEqual(['foo'], list(self.fconf.blaa))
self.assertEqual(2, len(self.fconf))
self.assertEqual(1, len(self.fconf.blaa))
self.assertNotIn('blaa', self.conf)
self.assertEqual(1, len(self.conf))
self.assertRaises(cfg.NoSuchOptError, getattr, self.conf, 'blaa')
def test_register_grouped_opt_none_default(self):
self.fconf.register_opt(cfg.StrOpt('foo'), group='blaa')
self.assertIsNone(self.fconf.blaa.foo)
self.assertIsNone(self.fconf['blaa']['foo'])
self.assertIn('blaa', self.fconf)
self.assertIn('foo', self.fconf.blaa)
self.assertEqual(set(['config_source', 'blaa']), set(self.fconf))
self.assertEqual(['foo'], list(self.fconf.blaa))
self.assertEqual(2, len(self.fconf))
self.assertEqual(1, len(self.fconf.blaa))
self.assertNotIn('blaa', self.conf)
self.assertEqual(1, len(self.conf))
self.assertRaises(cfg.NoSuchOptError, getattr, self.conf, 'blaa')
def test_register_group(self):
group = cfg.OptGroup('blaa')
self.fconf.register_group(group)
self.fconf.register_opt(cfg.StrOpt('foo'), group=group)
self.assertIsNone(self.fconf.blaa.foo)
self.assertIsNone(self.fconf['blaa']['foo'])
self.assertIn('blaa', self.fconf)
self.assertIn('foo', self.fconf.blaa)
self.assertEqual(set(['config_source', 'blaa']), set(self.fconf))
self.assertEqual(['foo'], list(self.fconf.blaa))
self.assertEqual(2, len(self.fconf))
self.assertEqual(1, len(self.fconf.blaa))
self.assertNotIn('blaa', self.conf)
self.assertEqual(1, len(self.conf))
self.assertRaises(cfg.NoSuchOptError, getattr, self.conf, 'blaa')
def test_register_opts(self):
self.fconf.register_opts([cfg.StrOpt('foo'),
cfg.StrOpt('bar')])
self.assertIn('foo', self.fconf)
self.assertIn('bar', self.fconf)
self.assertNotIn('foo', self.conf)
self.assertNotIn('bar', self.conf)
def test_register_known_cli_opt(self):
self.conf.register_opt(cfg.StrOpt('foo'))
self.fconf.register_cli_opt(cfg.StrOpt('foo'))
self.assertIn('foo', self.fconf)
self.assertIn('foo', self.conf)
def test_register_unknown_cli_opt(self):
with testtools.ExpectedException(cfgfilter.CliOptRegisteredError):
self.fconf.register_cli_opt(cfg.StrOpt('foo'))
def test_register_known_cli_opts(self):
self.conf.register_cli_opts([cfg.StrOpt('foo'), cfg.StrOpt('bar')])
self.fconf.register_cli_opts([cfg.StrOpt('foo'), cfg.StrOpt('bar')])
self.assertIn('foo', self.fconf)
self.assertIn('bar', self.fconf)
self.assertIn('foo', self.conf)
self.assertIn('bar', self.conf)
def test_register_unknown_cli_opts(self):
self.conf.register_cli_opt(cfg.StrOpt('foo'))
with testtools.ExpectedException(cfgfilter.CliOptRegisteredError):
self.fconf.register_cli_opts([
cfg.StrOpt('foo'),
cfg.StrOpt('bar')
])
def test_register_opts_grouped(self):
self.fconf.register_opts([cfg.StrOpt('foo'), cfg.StrOpt('bar')],
group='blaa')
self.assertIn('foo', self.fconf.blaa)
self.assertIn('bar', self.fconf.blaa)
self.assertNotIn('blaa', self.conf)
def test_register_known_cli_opt_grouped(self):
self.conf.register_cli_opt(cfg.StrOpt('foo'), group='blaa')
self.fconf.register_cli_opt(cfg.StrOpt('foo'), group='blaa')
self.assertIn('foo', self.fconf.blaa)
self.assertIn('blaa', self.fconf)
self.assertIn('blaa', self.conf)
def test_register_unknown_cli_opt_grouped(self):
with testtools.ExpectedException(cfgfilter.CliOptRegisteredError):
self.fconf.register_cli_opt(cfg.StrOpt('foo'), group='blaa')
def test_register_known_cli_opts_grouped(self):
self.conf.register_cli_opts([cfg.StrOpt('foo'), cfg.StrOpt('bar')],
group='blaa')
self.fconf.register_cli_opts([cfg.StrOpt('foo'), cfg.StrOpt('bar')],
group='blaa')
self.assertIn('foo', self.fconf.blaa)
self.assertIn('bar', self.fconf.blaa)
self.assertIn('blaa', self.fconf)
self.assertIn('blaa', self.conf)
def test_register_unknown_opts_grouped(self):
self.conf.register_cli_opts([cfg.StrOpt('bar')], group='blaa')
with testtools.ExpectedException(cfgfilter.CliOptRegisteredError):
self.fconf.register_cli_opts([
cfg.StrOpt('foo'),
cfg.StrOpt('bar')
], group='blaa')
def test_unknown_opt(self):
self.assertNotIn('foo', self.fconf)
self.assertEqual(1, len(self.fconf))
self.assertRaises(cfg.NoSuchOptError, getattr, self.fconf, 'foo')
self.assertNotIn('blaa', self.conf)
def test_blocked_opt(self):
self.conf.register_opt(cfg.StrOpt('foo'))
self.assertIn('foo', self.conf)
self.assertEqual(2, len(self.conf))
self.assertIsNone(self.conf.foo)
self.assertNotIn('foo', self.fconf)
self.assertEqual(1, len(self.fconf))
self.assertRaises(cfg.NoSuchOptError, getattr, self.fconf, 'foo')
def test_already_registered_opt(self):
self.conf.register_opt(cfg.StrOpt('foo'))
self.fconf.register_opt(cfg.StrOpt('foo'))
self.assertIn('foo', self.conf)
self.assertEqual(2, len(self.conf))
self.assertIsNone(self.conf.foo)
self.assertIn('foo', self.fconf)
self.assertEqual(2, len(self.fconf))
self.assertIsNone(self.fconf.foo)
self.conf.set_override('foo', 'bar')
self.assertEqual('bar', self.conf.foo)
self.assertEqual('bar', self.fconf.foo)
def test_already_registered_opts(self):
self.conf.register_opts([cfg.StrOpt('foo'),
cfg.StrOpt('fu')])
self.fconf.register_opts([cfg.StrOpt('foo'),
cfg.StrOpt('bu')])
self.assertIn('foo', self.conf)
self.assertIn('fu', self.conf)
self.assertNotIn('bu', self.conf)
self.assertEqual(3, len(self.conf))
self.assertIsNone(self.conf.foo)
self.assertIsNone(self.conf.fu)
self.assertIn('foo', self.fconf)
self.assertIn('bu', self.fconf)
self.assertNotIn('fu', self.fconf)
self.assertEqual(3, len(self.fconf))
self.assertIsNone(self.fconf.foo)
self.assertIsNone(self.fconf.bu)
self.conf.set_override('foo', 'bar')
self.assertEqual('bar', self.conf.foo)
self.assertEqual('bar', self.fconf.foo)
def test_already_registered_cli_opt(self):
self.conf.register_cli_opt(cfg.StrOpt('foo'))
self.fconf.register_cli_opt(cfg.StrOpt('foo'))
self.assertIn('foo', self.conf)
self.assertEqual(2, len(self.conf))
self.assertIsNone(self.conf.foo)
self.assertIn('foo', self.fconf)
self.assertEqual(2, len(self.fconf))
self.assertIsNone(self.fconf.foo)
self.conf.set_override('foo', 'bar')
self.assertEqual('bar', self.conf.foo)
self.assertEqual('bar', self.fconf.foo)
def test_already_registered_cli_opts(self):
self.conf.register_cli_opts([cfg.StrOpt('foo'),
cfg.StrOpt('fu')])
self.fconf.register_cli_opts([cfg.StrOpt('foo'),
cfg.StrOpt('fu')])
self.assertIn('foo', self.conf)
self.assertIn('fu', self.conf)
self.assertEqual(3, len(self.conf))
self.assertIsNone(self.conf.foo)
self.assertIsNone(self.conf.fu)
self.assertIn('foo', self.fconf)
self.assertIn('fu', self.fconf)
self.assertEqual(3, len(self.fconf))
self.assertIsNone(self.fconf.foo)
self.assertIsNone(self.fconf.fu)
self.conf.set_override('foo', 'bar')
self.assertEqual('bar', self.conf.foo)
self.assertEqual('bar', self.fconf.foo)
class ImportTestCase(BaseTestCase):
def setUp(self):
super(ImportTestCase, self).setUp(cfg.CONF)
def test_import_opt(self):
self.assertFalse(hasattr(self.conf, 'fblaa'))
self.conf.import_opt('fblaa', 'oslo_config.tests.testmods.fblaa_opt')
self.assertTrue(hasattr(self.conf, 'fblaa'))
self.assertFalse(hasattr(self.fconf, 'fblaa'))
self.fconf.import_opt('fblaa', 'oslo_config.tests.testmods.fblaa_opt')
self.assertTrue(hasattr(self.fconf, 'fblaa'))
def test_import_opt_in_group(self):
self.assertFalse(hasattr(self.conf, 'fbar'))
self.conf.import_opt('foo', 'oslo_config.tests.testmods.fbar_foo_opt',
group='fbar')
self.assertTrue(hasattr(self.conf, 'fbar'))
self.assertTrue(hasattr(self.conf.fbar, 'foo'))
self.assertFalse(hasattr(self.fconf, 'fbar'))
self.fconf.import_opt('foo', 'oslo_config.tests.testmods.fbar_foo_opt',
group='fbar')
self.assertTrue(hasattr(self.fconf, 'fbar'))
self.assertTrue(hasattr(self.fconf.fbar, 'foo'))
def test_import_group(self):
self.assertFalse(hasattr(self.conf, 'fbaar'))
self.conf.import_group('fbaar',
'oslo_config.tests.testmods.fbaar_baa_opt')
self.assertTrue(hasattr(self.conf, 'fbaar'))
self.assertTrue(hasattr(self.conf.fbaar, 'baa'))
self.assertFalse(hasattr(self.fconf, 'fbaar'))
self.fconf.import_group('fbaar',
'oslo_config.tests.testmods.fbaar_baa_opt')
self.assertTrue(hasattr(self.fconf, 'fbaar'))
self.assertTrue(hasattr(self.fconf.fbaar, 'baa'))
class ExposeTestCase(BaseTestCase):
def test_expose_opt(self):
self.assertFalse(hasattr(self.conf, 'foo'))
self.assertFalse(hasattr(self.fconf, 'foo'))
self.conf.register_opt(cfg.StrOpt('foo'))
self.conf.set_override('foo', 'bar')
self.assertTrue(hasattr(self.conf, 'foo'))
self.assertEqual('bar', self.conf.foo)
self.assertFalse(hasattr(self.fconf, 'foo'))
self.fconf.expose_opt('foo')
self.assertTrue(hasattr(self.conf, 'foo'))
self.assertTrue(hasattr(self.fconf, 'foo'))
self.assertEqual('bar', self.fconf.foo)
def test_expose_opt_with_group(self):
self.assertFalse(hasattr(self.conf, 'foo'))
self.assertFalse(hasattr(self.fconf, 'foo'))
self.conf.register_opt(cfg.StrOpt('foo'), group='group')
self.conf.set_override('foo', 'bar', group='group')
self.assertTrue(hasattr(self.conf.group, 'foo'))
self.assertEqual('bar', self.conf.group.foo)
self.assertFalse(hasattr(self.fconf, 'group'))
self.fconf.expose_opt('foo', group='group')
self.assertTrue(hasattr(self.conf.group, 'foo'))
self.assertTrue(hasattr(self.fconf.group, 'foo'))
self.assertEqual('bar', self.fconf.group.foo)
def test_expose_group(self):
self.conf.register_opts([cfg.StrOpt('foo'),
cfg.StrOpt('bar')], group='group')
self.conf.register_opts([cfg.StrOpt('foo'),
cfg.StrOpt('bar')], group='another')
self.conf.set_override('foo', 'a', group='group')
self.conf.set_override('bar', 'b', group='group')
self.fconf.expose_group('group')
self.assertEqual('a', self.fconf.group.foo)
self.assertEqual('b', self.fconf.group.bar)
self.assertFalse(hasattr(self.fconf, 'another'))
self.assertTrue(hasattr(self.conf, 'another'))