7 Oct 09:47
[MERGE] Fix two bugs in api versioning support - 279447 and 279451
From: Robert Collins <robertc <at> robertcollins.net>
Subject: [MERGE] Fix two bugs in api versioning support - 279447 and 279451
Newsgroups: gmane.comp.version-control.bazaar-ng.general
Date: 2008-10-07 07:48:33 GMT
Subject: [MERGE] Fix two bugs in api versioning support - 279447 and 279451
Newsgroups: gmane.comp.version-control.bazaar-ng.general
Date: 2008-10-07 07:48:33 GMT
This tries to make the api support in bzr more suitable for bzr-svn. -Rob -- GPG key available at: <http://www.robertcollins.net/keys.txt>.
# Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: robertc <at> robertcollins.net-20081007064146-\ # d1w8jhf0zqn1mb3y # target_branch: http://bazaar-vcs.org/bzr/bzr.dev # testament_sha1: 7b86672ecc8bc10a0d1fe37ee0a6814f7fc30fcd # timestamp: 2008-10-07 18:45:03 +1100 # source_branch: http://people.ubuntu.com/~robertc/baz2.0/api # base_revision_id: pqm <at> pqm.ubuntu.com-20081006223227-11nq4m186th9ljeq # # Begin patch === modified file 'NEWS' --- NEWS 2008-10-03 00:18:15 +0000 +++ NEWS 2008-10-07 06:41:46 +0000 @@ -79,6 +79,12 @@ BUG FIXES: + * API versioning support now has a multiple-version checking api + ``require_any_api``. (Robert Collins, #279447) + + * A failure to load a plugin due to an IncompatibleAPI exception is + now correctly reported. (Robert Collins, #279451) + * Branching from a shared repository on a smart server into a new repository now preserves the repository format. (Andrew Bennetts, #269214) === modified file 'bzrlib/api.py' --- bzrlib/api.py 2007-06-26 08:52:20 +0000 +++ bzrlib/api.py 2008-10-07 04:51:25 +0000 @@ -80,3 +80,24 @@ minimum = get_minimum_api_version(object_with_api) if wanted_api < minimum or wanted_api > current: raise IncompatibleAPI(object_with_api, wanted_api, minimum, current) + +def require_any_api(object_with_api, wanted_api_list): + """Check if object_with_api supports the api version wanted_api. + + :param object_with_api: An object which exports an API minimum and current + version. See get_minimum_api_version and get_current_api_version for + details. + :param wanted_api: A list of API versions, any of which being available is + sufficent. + :return None: + :raises IncompatibleAPI: When the wanted_api is not supported by + object_with_api. + + Added in bzrlib 1.9. + """ + for api in wanted_api_list[:-1]: + try: + return require_api(object_with_api, api) + except IncompatibleAPI: + pass + require_api(object_with_api, wanted_api_list[-1]) === modified file 'bzrlib/plugin.py' --- bzrlib/plugin.py 2008-09-08 12:59:00 +0000 +++ bzrlib/plugin.py 2008-10-07 06:41:46 +0000 @@ -43,6 +43,7 @@ from bzrlib import ( config, debug, + errors, osutils, trace, ) @@ -172,7 +173,10 @@ def load_from_dir(d): - """Load the plugins in directory d.""" + """Load the plugins in directory d. + + d must be in the plugins module path already. + """ # Get the list of valid python suffixes for __init__.py? # this includes .py, .pyc, and .pyo (depending on if we are running -O) # but it doesn't include compiled modules (.so, .dll, etc) @@ -210,7 +214,13 @@ exec "import bzrlib.plugins.%s" % name in {} except KeyboardInterrupt: raise + except errors.IncompatibleAPI, e: + trace.warning("Unable to load plugin %r. It requested API version " + "%s of module %s but the minimum exported version is %s, and " + "the maximum is %s" % + (name, e.wanted, e.api, e.minimum, e.current)) except Exception, e: + trace.warning("%s" % e) ## import pdb; pdb.set_trace() if re.search('\.|-| ', name): sanitised_name = re.sub('[-. ]', '_', name) === modified file 'bzrlib/tests/test_api.py' --- bzrlib/tests/test_api.py 2007-06-26 08:52:20 +0000 +++ bzrlib/tests/test_api.py 2008-10-07 04:51:25 +0000 @@ -71,6 +71,31 @@ self.assertEqual(bzrlib.version_info[0:3], bzrlib.api.get_current_api_version(an_object)) + def test_require_any_api_wanted_one(self): + an_object = TrivialObject() + an_object.api_minimum_version = (1, 2, 3) + an_object.api_current_version = (4, 5, 6) + bzrlib.api.require_any_api(an_object, [(1, 2, 3)]) + + def test_require_any_api_wanted_first_compatible(self): + an_object = TrivialObject() + an_object.api_minimum_version = (1, 2, 3) + an_object.api_current_version = (4, 5, 6) + bzrlib.api.require_any_api(an_object, [(1, 2, 3), (5, 6, 7)]) + + def test_require_any_api_wanted_second_compatible(self): + an_object = TrivialObject() + an_object.api_minimum_version = (1, 2, 3) + an_object.api_current_version = (4, 5, 6) + bzrlib.api.require_any_api(an_object, [(5, 6, 7), (1, 2, 3)]) + + def test_require_any_api_wanted_none_compatible(self): + an_object = TrivialObject() + an_object.api_minimum_version = (1, 2, 3) + an_object.api_current_version = (4, 5, 6) + self.assertRaises(IncompatibleAPI, bzrlib.api.require_any_api, + an_object, [(1, 2, 2), (5, 6, 7)]) + def test_require_api_wanted_is_minimum_is_ok(self): an_object = TrivialObject() an_object.api_minimum_version = (1, 2, 3) === modified file 'bzrlib/tests/test_plugins.py' --- bzrlib/tests/test_plugins.py 2008-08-11 12:50:16 +0000 +++ bzrlib/tests/test_plugins.py 2008-10-07 06:41:46 +0000 @@ -193,30 +193,60 @@ del bzrlib.plugins.ts_plugin self.failIf(getattr(bzrlib.plugins, 'ts_plugin', None)) - def test_plugin_with_bad_name_does_not_load(self): - # Create badly-named plugin - file('bzr-bad plugin-name..py', 'w').close() - + def load_and_capture(self, name): + """Load plugins from '.' capturing the output. + + :param name: The name of the plugin. + :return: A string with the log from the plugin loading call. + """ # Capture output stream = StringIO() - handler = logging.StreamHandler(stream) - log = logging.getLogger('bzr') - log.addHandler(handler) - - bzrlib.plugin.load_from_dir('.') - - # Stop capturing output - handler.flush() - handler.close() - log.removeHandler(handler) - - self.assertContainsRe(stream.getvalue(), + try: + handler = logging.StreamHandler(stream) + log = logging.getLogger('bzr') + log.addHandler(handler) + try: + try: + bzrlib.plugin.load_from_path(['.']) + finally: + if 'bzrlib.plugins.%s' % name in sys.modules: + del sys.modules['bzrlib.plugins.%s' % name] + if getattr(bzrlib.plugins, name, None): + delattr(bzrlib.plugins, name) + finally: + # Stop capturing output + handler.flush() + handler.close() + log.removeHandler(handler) + return stream.getvalue() + finally: + stream.close() + + def test_plugin_with_bad_api_version_reports(self): + # This plugin asks for bzrlib api version 1.0.0, which is not supported + # anymore. + name = 'wants100.py' + f = file(name, 'w') + try: + f.write("import bzrlib.api\n" + "bzrlib.api.require_any_api(bzrlib, [(1, 0, 0)])\n") + finally: + f.close() + + log = self.load_and_capture(name) + self.assertContainsRe(log, + r"It requested API version") + + def test_plugin_with_bad_name_does_not_load(self): + # The file name here invalid for a python module. + name = 'bzr-bad plugin-name..py' + file(name, 'w').close() + log = self.load_and_capture(name) + self.assertContainsRe(log, r"Unable to load 'bzr-bad plugin-name\.' in '\.' as a plugin " "because the file path isn't a valid module name; try renaming " "it to 'bad_plugin_name_'\.") - stream.close() - class TestPlugins(TestCaseInTempDir): # Begin bundle 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 gLgWhIJ4/uLuSKcKEgItAoSA
RSS Feed