24
from oslo_config import cfg
22
25
import pkg_resources
24
from ironic.openstack.common.gettextutils import _
25
from ironic.openstack.common import log as logging
28
from ironic.openstack.common._i18n import _
28
31
LOG = logging.getLogger(__name__)
36
cfg.BoolOpt('fatal_deprecations',
38
help='Enables or disables fatal status of deprecations.'),
31
42
class deprecated(object):
116
129
self.remove_in = remove_in
119
def __call__(self, func):
132
def __call__(self, func_or_cls):
120
133
if not self.what:
121
self.what = func.__name__ + '()'
123
@functools.wraps(func)
124
def wrapped(*args, **kwargs):
125
msg, details = self._build_message()
126
LOG.deprecated(msg, details)
127
return func(*args, **kwargs)
134
self.what = func_or_cls.__name__ + '()'
135
msg, details = self._build_message()
137
if inspect.isfunction(func_or_cls):
139
@six.wraps(func_or_cls)
140
def wrapped(*args, **kwargs):
141
report_deprecated_feature(LOG, msg, details)
142
return func_or_cls(*args, **kwargs)
144
elif inspect.isclass(func_or_cls):
145
orig_init = func_or_cls.__init__
147
# TODO(tsufiev): change `functools` module to `six` as
148
# soon as six 1.7.4 (with fix for passing `assigned`
149
# argument to underlying `functools.wraps`) is released
150
# and added to the oslo-incubator requrements
151
@functools.wraps(orig_init, assigned=('__name__', '__doc__'))
152
def new_init(self, *args, **kwargs):
153
report_deprecated_feature(LOG, msg, details)
154
orig_init(self, *args, **kwargs)
155
func_or_cls.__init__ = new_init
158
raise TypeError('deprecated can be used only with functions or '
130
161
def _get_safe_to_remove_release(self, release):
131
162
# TODO(dstanek): this method will have to be reimplemented once
183
214
return current_parts >= requested_parts
217
# Track the messages we have sent already. See
218
# report_deprecated_feature().
219
_deprecated_messages_sent = {}
222
def report_deprecated_feature(logger, msg, *args, **kwargs):
223
"""Call this function when a deprecated feature is used.
225
If the system is configured for fatal deprecations then the message
226
is logged at the 'critical' level and :class:`DeprecatedConfig` will
229
Otherwise, the message will be logged (once) at the 'warn' level.
231
:raises: :class:`DeprecatedConfig` if the system is configured for
234
stdmsg = _("Deprecated: %s") % msg
235
CONF.register_opts(opts)
236
if CONF.fatal_deprecations:
237
logger.critical(stdmsg, *args, **kwargs)
238
raise DeprecatedConfig(msg=stdmsg)
240
# Using a list because a tuple with dict can't be stored in a set.
241
sent_args = _deprecated_messages_sent.setdefault(msg, list())
243
if args in sent_args:
244
# Already logged this message, so don't log it again.
247
sent_args.append(args)
248
logger.warn(stdmsg, *args, **kwargs)
251
class DeprecatedConfig(Exception):
252
message = _("Fatal call to deprecated config: %(msg)s")
254
def __init__(self, msg):
255
super(Exception, self).__init__(self.message % dict(msg=msg))