From bbf48f00cd4bce5c127acacc0f1847e1b7414264 Mon Sep 17 00:00:00 2001 From: Doug Hellmann Date: Wed, 24 Sep 2014 17:57:58 -0400 Subject: [PATCH] Remove oslo.log code and clean up versionutils API Remove the modules and tests that have moved to oslo.log. Replace the use of oslo.log with the standard library logging module. Replace calls to LOG.deprecated() with a new function in versionutils that is copied from the body of the old implementation. Add fatal_deprecations configuration option to versionutils, where it is used now instead of the old log module. Change-Id: I5903f9a9c521789cbf3381d9741a8a5308767e2d Closes-Bug: #1373120 Blueprint: fix-import-cycle-log-and-versionutils --- openstack/common/versionutils.py | 56 +++++++++++++++++++++-- tests/unit/test_versionutils.py | 76 +++++++++++++++++--------------- 2 files changed, 93 insertions(+), 39 deletions(-) diff --git a/openstack/common/versionutils.py b/openstack/common/versionutils.py index 13259a3b..2865b7db 100644 --- a/openstack/common/versionutils.py +++ b/openstack/common/versionutils.py @@ -19,15 +19,24 @@ Helpers for comparing version strings. import functools import inspect +import logging +from oslo.config import cfg import pkg_resources import six from openstack.common._i18n import _ -from openstack.common import log as logging LOG = logging.getLogger(__name__) +CONF = cfg.CONF + + +opts = [ + cfg.BoolOpt('fatal_deprecations', + default=False, + help='Enables or disables fatal status of deprecations.'), +] class deprecated(object): @@ -127,7 +136,7 @@ class deprecated(object): @six.wraps(func_or_cls) def wrapped(*args, **kwargs): - LOG.deprecated(msg, details) + report_deprecated_feature(LOG, msg, details) return func_or_cls(*args, **kwargs) return wrapped elif inspect.isclass(func_or_cls): @@ -139,7 +148,7 @@ class deprecated(object): # and added to the oslo-incubator requrements @functools.wraps(orig_init, assigned=('__name__', '__doc__')) def new_init(self, *args, **kwargs): - LOG.deprecated(msg, details) + report_deprecated_feature(LOG, msg, details) orig_init(self, *args, **kwargs) func_or_cls.__init__ = new_init return func_or_cls @@ -201,3 +210,44 @@ def is_compatible(requested_version, current_version, same_major=True): return False return current_parts >= requested_parts + + +# Track the messages we have sent already. See +# report_deprecated_feature(). +_deprecated_messages_sent = {} + + +def report_deprecated_feature(logger, msg, *args, **kwargs): + """Call this function when a deprecated feature is used. + + If the system is configured for fatal deprecations then the message + is logged at the 'critical' level and :class:`DeprecatedConfig` will + be raised. + + Otherwise, the message will be logged (once) at the 'warn' level. + + :raises: :class:`DeprecatedConfig` if the system is configured for + fatal deprecations. + """ + stdmsg = _("Deprecated: %s") % msg + CONF.register_opts(opts) + if CONF.fatal_deprecations: + logger.critical(stdmsg, *args, **kwargs) + raise DeprecatedConfig(msg=stdmsg) + + # Using a list because a tuple with dict can't be stored in a set. + sent_args = _deprecated_messages_sent.setdefault(msg, list()) + + if args in sent_args: + # Already logged this message, so don't log it again. + return + + sent_args.append(args) + logger.warn(stdmsg, *args, **kwargs) + + +class DeprecatedConfig(Exception): + message = _("Fatal call to deprecated config: %(msg)s") + + def __init__(self, msg): + super(Exception, self).__init__(self.message % dict(msg=msg)) diff --git a/tests/unit/test_versionutils.py b/tests/unit/test_versionutils.py index 00481690..4cb3aabb 100644 --- a/tests/unit/test_versionutils.py +++ b/tests/unit/test_versionutils.py @@ -21,7 +21,7 @@ from openstack.common import versionutils class DeprecatedTestCase(test_base.BaseTestCase): - def assert_deprecated(self, mock_log, no_removal=False, + def assert_deprecated(self, mock_reporter, no_removal=False, **expected_details): decorator = versionutils.deprecated if 'in_favor_of' in expected_details: @@ -38,10 +38,14 @@ class DeprecatedTestCase(test_base.BaseTestCase): expected_msg = getattr( decorator, '_deprecated_msg_with_no_alternative_no_removal') - mock_log.deprecated.assert_called_with(expected_msg, expected_details) + # The first argument is the logger, and we don't care about + # that, so ignore it with ANY. + mock_reporter.assert_called_with(mock.ANY, + expected_msg, + expected_details) - @mock.patch('openstack.common.versionutils.LOG', mock.Mock()) - def test_deprecating_a_function_returns_correct_value(self): + @mock.patch('openstack.common.versionutils.report_deprecated_feature') + def test_deprecating_a_function_returns_correct_value(self, mock_reporter): @versionutils.deprecated(as_of=versionutils.deprecated.ICEHOUSE) def do_outdated_stuff(data): @@ -52,8 +56,8 @@ class DeprecatedTestCase(test_base.BaseTestCase): self.assertThat(retval, matchers.Equals(expected_rv)) - @mock.patch('openstack.common.versionutils.LOG', mock.Mock()) - def test_deprecating_a_method_returns_correct_value(self): + @mock.patch('openstack.common.versionutils.report_deprecated_feature') + def test_deprecating_a_method_returns_correct_value(self, mock_reporter): class C(object): @versionutils.deprecated(as_of=versionutils.deprecated.ICEHOUSE) @@ -64,8 +68,8 @@ class DeprecatedTestCase(test_base.BaseTestCase): self.assertThat(retval, matchers.Equals((1, 'of anything'))) - @mock.patch('openstack.common.versionutils.LOG') - def test_deprecated_with_unknown_future_release(self, mock_log): + @mock.patch('openstack.common.versionutils.report_deprecated_feature') + def test_deprecated_with_unknown_future_release(self, mock_reporter): @versionutils.deprecated(as_of=versionutils.deprecated.BEXAR, in_favor_of='different_stuff()') @@ -74,14 +78,14 @@ class DeprecatedTestCase(test_base.BaseTestCase): do_outdated_stuff() - self.assert_deprecated(mock_log, + self.assert_deprecated(mock_reporter, what='do_outdated_stuff()', in_favor_of='different_stuff()', as_of='Bexar', remove_in='D') - @mock.patch('openstack.common.versionutils.LOG') - def test_deprecated_with_known_future_release(self, mock_log): + @mock.patch('openstack.common.versionutils.report_deprecated_feature') + def test_deprecated_with_known_future_release(self, mock_reporter): @versionutils.deprecated(as_of=versionutils.deprecated.GRIZZLY, in_favor_of='different_stuff()') @@ -90,14 +94,14 @@ class DeprecatedTestCase(test_base.BaseTestCase): do_outdated_stuff() - self.assert_deprecated(mock_log, + self.assert_deprecated(mock_reporter, what='do_outdated_stuff()', in_favor_of='different_stuff()', as_of='Grizzly', remove_in='Icehouse') - @mock.patch('openstack.common.versionutils.LOG') - def test_deprecated_without_replacement(self, mock_log): + @mock.patch('openstack.common.versionutils.report_deprecated_feature') + def test_deprecated_without_replacement(self, mock_reporter): @versionutils.deprecated(as_of=versionutils.deprecated.GRIZZLY) def do_outdated_stuff(): @@ -105,13 +109,13 @@ class DeprecatedTestCase(test_base.BaseTestCase): do_outdated_stuff() - self.assert_deprecated(mock_log, + self.assert_deprecated(mock_reporter, what='do_outdated_stuff()', as_of='Grizzly', remove_in='Icehouse') - @mock.patch('openstack.common.versionutils.LOG') - def test_deprecated_with_custom_what(self, mock_log): + @mock.patch('openstack.common.versionutils.report_deprecated_feature') + def test_deprecated_with_custom_what(self, mock_reporter): @versionutils.deprecated(as_of=versionutils.deprecated.GRIZZLY, what='v2.0 API', @@ -121,14 +125,14 @@ class DeprecatedTestCase(test_base.BaseTestCase): do_outdated_stuff() - self.assert_deprecated(mock_log, + self.assert_deprecated(mock_reporter, what='v2.0 API', in_favor_of='v3 API', as_of='Grizzly', remove_in='Icehouse') - @mock.patch('openstack.common.versionutils.LOG') - def test_deprecated_with_removed_next_release(self, mock_log): + @mock.patch('openstack.common.versionutils.report_deprecated_feature') + def test_deprecated_with_removed_next_release(self, mock_reporter): @versionutils.deprecated(as_of=versionutils.deprecated.GRIZZLY, remove_in=1) @@ -137,13 +141,13 @@ class DeprecatedTestCase(test_base.BaseTestCase): do_outdated_stuff() - self.assert_deprecated(mock_log, + self.assert_deprecated(mock_reporter, what='do_outdated_stuff()', as_of='Grizzly', remove_in='Havana') - @mock.patch('openstack.common.versionutils.LOG') - def test_deprecated_with_removed_plus_3(self, mock_log): + @mock.patch('openstack.common.versionutils.report_deprecated_feature') + def test_deprecated_with_removed_plus_3(self, mock_reporter): @versionutils.deprecated(as_of=versionutils.deprecated.GRIZZLY, remove_in=+3) @@ -152,27 +156,27 @@ class DeprecatedTestCase(test_base.BaseTestCase): do_outdated_stuff() - self.assert_deprecated(mock_log, + self.assert_deprecated(mock_reporter, what='do_outdated_stuff()', as_of='Grizzly', remove_in='Juno') - @mock.patch('openstack.common.versionutils.LOG') - def test_deprecated_with_removed_zero(self, mock_log): + @mock.patch('openstack.common.versionutils.report_deprecated_feature') + def test_deprecated_with_removed_zero(self, mock_reporter): @versionutils.deprecated(as_of=versionutils.deprecated.GRIZZLY, remove_in=0) def do_outdated_stuff(): return do_outdated_stuff() - self.assert_deprecated(mock_log, + self.assert_deprecated(mock_reporter, no_removal=True, what='do_outdated_stuff()', as_of='Grizzly', remove_in='Grizzly') - @mock.patch('openstack.common.versionutils.LOG') - def test_deprecated_with_removed_zero_and_alternative(self, mock_log): + @mock.patch('openstack.common.versionutils.report_deprecated_feature') + def test_deprecated_with_removed_zero_and_alternative(self, mock_reporter): @versionutils.deprecated(as_of=versionutils.deprecated.GRIZZLY, in_favor_of='different_stuff()', remove_in=0) @@ -180,15 +184,15 @@ class DeprecatedTestCase(test_base.BaseTestCase): return do_outdated_stuff() - self.assert_deprecated(mock_log, + self.assert_deprecated(mock_reporter, no_removal=True, what='do_outdated_stuff()', as_of='Grizzly', in_favor_of='different_stuff()', remove_in='Grizzly') - @mock.patch('openstack.common.versionutils.LOG') - def test_deprecated_class_without_init(self, mock_log): + @mock.patch('openstack.common.versionutils.report_deprecated_feature') + def test_deprecated_class_without_init(self, mock_reporter): @versionutils.deprecated(as_of=versionutils.deprecated.JUNO, remove_in=+1) @@ -197,13 +201,13 @@ class DeprecatedTestCase(test_base.BaseTestCase): obj = OutdatedClass() self.assertIsInstance(obj, OutdatedClass) - self.assert_deprecated(mock_log, + self.assert_deprecated(mock_reporter, what='OutdatedClass()', as_of='Juno', remove_in='Kilo') - @mock.patch('openstack.common.versionutils.LOG') - def test_deprecated_class_with_init(self, mock_log): + @mock.patch('openstack.common.versionutils.report_deprecated_feature') + def test_deprecated_class_with_init(self, mock_reporter): mock_arguments = mock.MagicMock() args = (1, 5, 7) kwargs = {'first': 10, 'second': 20} @@ -223,7 +227,7 @@ class DeprecatedTestCase(test_base.BaseTestCase): self.assertEqual('It is __init__ method.', obj.__init__.__doc__) self.assertEqual(args, mock_arguments.args) self.assertEqual(kwargs, mock_arguments.kwargs) - self.assert_deprecated(mock_log, + self.assert_deprecated(mock_reporter, what='OutdatedClass()', as_of='Juno', remove_in='Kilo')