# HG changeset patch # User Jeff Hammel # Date 1335893617 25200 # Node ID c530f6265deb5a1580d0b7c384839bc45c42c58c # Parent f4590492cb4c07ce5657d2ad4754961d7c3ec555 allow extensible configuration; also start using deepcopy heavily since otherwise you have artefacts diff -r f4590492cb4c -r c530f6265deb configuration/configuration.py --- a/configuration/configuration.py Mon Apr 30 13:21:48 2012 -0700 +++ b/configuration/configuration.py Tue May 01 10:33:37 2012 -0700 @@ -225,6 +225,7 @@ options = {} # configuration basis definition load_option = 'load' # where to put the load option + extend = set() # if dicts/lists should be extended def __init__(self, configuration_providers=configuration_providers, types=types, load=None, dump='--dump', **parser_args): @@ -326,17 +327,24 @@ ### methods for adding configuration + def default_config(self): + """configuration defaults""" + defaults = {} + for key, value in self.options.items(): + if 'default' in value: + defaults[key] = value['default'] + return copy.deepcopy(defaults) + def __call__(self, *args): """add items to configuration and check it""" + # start with defaults + self.config = self.default_config() + + # add the configuration for config in args: self.add(config) - # add defaults if not present - for key, value in self.items(): - if 'default' in value and key not in self.config: - self.config[key] = value['default'] - # validate total configuration self.validate() # TODO: configuration should be locked after this is called @@ -344,9 +352,24 @@ def add(self, config, check=True): """update configuration: not undoable""" - self.check(config) # check config to be added - self.config.update(config) - # TODO: option to extend; augment lists/dicts + # check config to be added + self.check(config) + + # add the configuration + for key, value in config.items(): + value = copy.deepcopy(value) + if key in self.extend and key in self.config: + type1 = type(self.config[key]) + type2 = type(value) + assert type1 == type2 # XXX hack + if type1 == dict: + self.config[key].update(value) + elif type1 == list: + self.config[key].extend(value) + else: + raise NotImplementedError + else: + self.config[key] = value ### methods for optparse ### XXX could go in a subclass diff -r f4590492cb4c -r c530f6265deb tests/base.json --- a/tests/base.json Mon Apr 30 13:21:48 2012 -0700 +++ b/tests/base.json Tue May 01 10:33:37 2012 -0700 @@ -3,5 +3,7 @@ "ts" ], "browser_path": "/home/jhammel/firefox/firefox", - "test_timeout": 60 + "test_timeout": 60, + "preferences": {"browser.bookmarks.max_backups": 0, + "browser.cache.disk.smart_size.enabled": false} } \ No newline at end of file diff -r f4590492cb4c -r c530f6265deb tests/example.py --- a/tests/example.py Mon Apr 30 13:21:48 2012 -0700 +++ b/tests/example.py Tue May 01 10:33:37 2012 -0700 @@ -17,9 +17,12 @@ 'type': bool}, 'test_timeout': {'help': "Time to wait for the browser to output to the log file", 'default': 1200}, - 'preferences': {'type': dict, + 'preferences': {'help': 'profile preferences', + 'default': {'browser.bookmarks.max_backups': 0, + 'browser.cache.disk.smart_size.enabled': False}, 'flags': ['-p', '--pref']} } + extend = set(['preferences']) if __name__ == '__main__': from pprint import pprint diff -r f4590492cb4c -r c530f6265deb tests/unit.py --- a/tests/unit.py Mon Apr 30 13:21:48 2012 -0700 +++ b/tests/unit.py Tue May 01 10:33:37 2012 -0700 @@ -59,6 +59,10 @@ 'activeTests': ['ts']} example(config) config['test_timeout'] = 1200 # default + config['preferences'] = {"browser.bookmarks.max_backups": 0, + "browser.cache.disk.smart_size.enabled": False} + + # ensure they are equal self.assertEqual(config, example.config) example.serialize(filename) self.assertTrue(os.path.exists(filename)) @@ -101,6 +105,7 @@ missingvalueexception = e self.assertTrue(isinstance(e, configuration.MissingValueException)) + def test_multiple_configurations(self): """test having multiple configurations""" @@ -141,5 +146,25 @@ config['test_timeout'] = 1200 self.assertEqual(example.config, config) + def test_extend(self): + + # default preferences + example = ExampleConfiguration() + default_prefs = {"browser.bookmarks.max_backups": 0, + "browser.cache.disk.smart_size.enabled": False} + example.parse_args(['-a', 'ts', '-e', '/opt/bin/firefox']) + self.assertEqual(example.config['preferences'], default_prefs) + + # now extend them + example = ExampleConfiguration() + default_prefs['network.dns.ipv4OnlyDomains'] = 'localhost' + tf = tempfile.mktemp() + f = file(tf, 'w') + f.write(json.dumps({'preferences': {'network.dns.ipv4OnlyDomains': 'localhost'}})) + f.close() + example.parse_args(['-a', 'ts', '-e', '/opt/bin/firefox', tf]) + self.assertEqual(example.config['preferences'], default_prefs) + os.remove(tf) + if __name__ == '__main__': unittest.main()