Rev 5451: Implement config.get_sections() to clarify how sections can be used. in file:///home/vila/src/bzr/experimental/config/
Vincent Ladeuil
v.ladeuil+lp at free.fr
Sat Oct 2 22:08:35 BST 2010
At file:///home/vila/src/bzr/experimental/config/
------------------------------------------------------------
revno: 5451
revision-id: v.ladeuil+lp at free.fr-20101002210835-nqy0fqas09e7ijj1
parent: v.ladeuil+lp at free.fr-20101001095208-vupdrq1jtle74gk7
committer: Vincent Ladeuil <v.ladeuil+lp at free.fr>
branch nick: config-modify
timestamp: Sat 2010-10-02 23:08:35 +0200
message:
Implement config.get_sections() to clarify how sections can be used.
* bzrlib/tests/test_config.py:
(TestConfigGetSections): Expose the various supported section
use-cases.
* bzrlib/config.py:
(IniBasedConfig.get_sections, GlobalConfig.get_sections)
(LocationConfig.get_sections, BranchConfig.get_sections): Properly
capture the different section usages exposed by the various config
objects.
-------------- next part --------------
=== modified file 'NEWS'
--- a/NEWS 2010-10-01 09:52:08 +0000
+++ b/NEWS 2010-10-02 21:08:35 +0000
@@ -43,10 +43,6 @@
API Changes
***********
-* ``bzrlib.config.IniBasedConfig`` objects now implement ``get_options`` that
- permit querying them for the options defined and their values.
- (Vincent Ladeuil)
-
Internals
*********
@@ -54,6 +50,12 @@
longer include the "log" information for tests which are considered to
be 'successes' (success, xfail, skip, etc) (John Arbash Meinel)
+* ``bzrlib.config.IniBasedConfig`` objects now implement ``get_options`` that
+ permit querying them for the options defined and their values and
+ ``get_sections()`` that return a list of (name, section) for the sections
+ walked by get_user_option() and used by set_user_option().
+ (Vincent Ladeuil)
+
Testing
*******
=== modified file 'bzrlib/config.py'
--- a/bzrlib/config.py 2010-10-01 09:52:08 +0000
+++ b/bzrlib/config.py 2010-10-02 21:08:35 +0000
@@ -450,6 +450,24 @@
"""Override this to define the section used by the config."""
return "DEFAULT"
+ def get_sections(self, name=None):
+ """Returns an iterator of the sections specified by ``name``.
+
+ :param name: The section name. If None is supplied, the default
+ configurations are yielded.
+
+ :return: A tuple (name, section) for all sections that will we walked
+ by user_get_option() in the 'right' order. The first one is where
+ set_user_option() will update the value.
+ """
+ parser = self._get_parser()
+ if name is not None:
+ yield (name, parser[name])
+ else:
+ # No section name has been given so we fallback to the configobj
+ # itself which holds the variables defined outside of any section.
+ yield (None, parser)
+
def get_options(self, sections=None):
"""Return an ordered list of (name, value, section, config_id) tuples.
@@ -706,6 +724,19 @@
self._write_config_file()
+ def get_sections(self, name=None):
+ """See IniBasedConfig.get_sections()."""
+ parser = self._get_parser()
+ # We don't give access to options defined outside of any section, we
+ # used the DEFAULT section by... default.
+ if name in (None, 'DEFAULT'):
+ # This could happen for an empty file where the DEFAULT section
+ # doesn't exist yet. So we force DEFAULT when yielding
+ name = 'DEFAULT'
+ parser[name]= {}
+ yield (name, parser[name])
+
+
class LocationConfig(LockableConfig):
"""A configuration object that gives the policy for a location."""
@@ -783,6 +814,14 @@
pass
return sections
+ def get_sections(self, name=None):
+ """See IniBasedConfig.get_sections()."""
+ # We ignore the name here as the only sections handled are named with
+ # the location path and we don't expose embedded sections either.
+ parser = self._get_parser()
+ for name, extra_path in self._get_matching_sections():
+ yield (name, parser[name])
+
def _get_option_policy(self, section, option_name):
"""Return the policy for the given (section, option_name) pair."""
# check for the old 'recurse=False' flag
@@ -946,6 +985,12 @@
return value
return None
+ def get_sections(self, name=None):
+ """See IniBasedConfig.get_sections()."""
+ for source in self.option_sources:
+ for section in source().get_sections(name):
+ yield section
+
def get_options(self, sections=None):
opts = []
# First the locations options
@@ -1605,8 +1650,8 @@
"""A Config that reads/writes a config file on a Transport.
It is a low-level object that considers config data to be name/value pairs
- that may be associated with a section. Assigning meaning to the these
- values is done at higher levels like TreeConfig.
+ that may be associated with a section. Assigning meaning to these values
+ is done at higher levels like TreeConfig.
"""
def __init__(self, transport, filename):
=== modified file 'bzrlib/tests/test_config.py'
--- a/bzrlib/tests/test_config.py 2010-10-01 09:52:08 +0000
+++ b/bzrlib/tests/test_config.py 2010-10-02 21:08:35 +0000
@@ -1471,15 +1471,18 @@
self.assertIs(None, bzrdir_config.get_default_stack_on())
-class TestConfigGetOptions(tests.TestCaseWithTransport):
+class TestWithConfigs(tests.TestCaseWithTransport):
def setUp(self):
- super(TestConfigGetOptions, self).setUp()
+ super(TestWithConfigs, self).setUp()
self.global_config = config.GlobalConfig()
- self.tree = self.make_branch_and_tree('.')
+ self.tree = self.make_branch_and_tree('tree')
self.branch_config = config.BranchConfig(self.tree.branch)
self.locations_config = config.LocationConfig(self.tree.basedir)
+
+class TestConfigGetOptions(TestWithConfigs):
+
def assertOptions(self, expected, conf):
actual = list(conf.get_options())
self.assertEqual(expected, actual)
@@ -1532,6 +1535,72 @@
self.branch_config)
+class TestConfigGetSections(TestWithConfigs):
+
+ def assertSectionNames(self, expected, conf, name=None):
+ """Check which sections are returned for a given config.
+
+ If fallback configurations exist their sections can be included.
+
+ :param expected: A list of section names.
+
+ :param conf: The configuration that will be queried.
+
+ :param name: An optional section name that will be passed to
+ get_sections().
+ """
+ sections = list(conf.get_sections(name))
+ self.assertLength(len(expected), sections)
+ self.assertEqual(expected, [name for name, section in sections])
+
+ def test_global_default_section(self):
+ self.assertSectionNames(['DEFAULT'], self.global_config)
+
+ def test_locations_default_section(self):
+ # No sections are defined in an empty file
+ self.assertSectionNames([], self.locations_config)
+
+ def test_locations_named_section(self):
+ self.locations_config.set_user_option('file', 'locations')
+ self.assertSectionNames([self.tree.basedir], self.locations_config)
+
+ def test_locations_matching_sections(self):
+ loc_config = self.locations_config
+ loc_config.set_user_option('file', 'locations')
+ # We need to cheat a bit here to create an option in sections above and
+ # below the 'location' one.
+ parser = loc_config._get_parser()
+ # locations.cong deals with '/' ignoring native os.sep
+ location_names = self.tree.basedir.split('/')
+ parent = '/'.join(location_names[:-1])
+ child = '/'.join(location_names + ['child'])
+ parser[parent] = {}
+ parser[parent]['file'] = 'parent'
+ parser[child] = {}
+ parser[child]['file'] = 'child'
+ self.assertSectionNames([self.tree.basedir, parent], loc_config)
+
+ def test_branch_data_default_section(self):
+ self.assertSectionNames([None],
+ self.branch_config._get_branch_data_config())
+
+ def test_branch_default_sections(self):
+ # No sections are defined in an empty locations file
+ self.assertSectionNames([None, 'DEFAULT'],
+ self.branch_config)
+ # Unless we define an option
+ self.branch_config._get_location_config().set_user_option(
+ 'file', 'locations')
+ self.assertSectionNames([self.tree.basedir, None, 'DEFAULT'],
+ self.branch_config)
+
+ def test_global_named_section(self):
+ # We need to cheat as the API doesn't give direct access to sections
+ # other than DEFAULT.
+ self.global_config.set_alias('bazaar', 'bzr')
+ self.assertSectionNames(['ALIASES'], self.global_config, 'ALIASES')
+
+
class TestAuthenticationConfigFile(tests.TestCase):
"""Test the authentication.conf file matching"""
More information about the bazaar-commits
mailing list