~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/symbol_versioning.py

  • Committer: Aaron Bentley
  • Date: 2012-07-19 16:57:16 UTC
  • mto: This revision was merged to the branch mainline in revision 6540.
  • Revision ID: aaron@aaronbentley.com-20120719165716-b4iupzkb17b9l9wx
Avoid branch write lock to preserve VFS call count.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006, 2007, 2008 Canonical Ltd
2
 
#   Authors: Robert Collins <robert.collins@canonical.com> and others
 
1
# Copyright (C) 2006-2010 Canonical Ltd
3
2
#
4
3
# This program is free software; you can redistribute it and/or modify
5
4
# it under the terms of the GNU General Public License as published by
13
12
#
14
13
# You should have received a copy of the GNU General Public License
15
14
# along with this program; if not, write to the Free Software
16
 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
16
 
18
17
"""Symbol versioning
19
18
 
20
19
The methods here allow for api symbol versioning.
21
20
"""
22
21
 
 
22
from __future__ import absolute_import
 
23
 
23
24
__all__ = ['deprecated_function',
24
25
           'deprecated_in',
25
26
           'deprecated_list',
28
29
           'deprecated_passed',
29
30
           'set_warning_method',
30
31
           'warn',
31
 
           'zero_seven',
32
 
           'zero_eight',
33
 
           'zero_nine',
34
 
           'zero_ten',
35
 
           'zero_eleven',
36
 
           'zero_twelve',
37
 
           'zero_thirteen',
38
 
           'zero_fourteen',
39
 
           'zero_fifteen',
40
 
           'zero_sixteen',
41
 
           'zero_seventeen',
42
 
           'zero_eighteen',
43
 
           'zero_ninety',
44
 
           'zero_ninetyone',
45
 
           'zero_ninetytwo',
46
 
           'zero_ninetythree',
47
 
           'one_zero',
48
 
           'one_one',
49
 
           'one_two',
50
 
           'one_three',
51
 
           'one_four',
52
 
           'one_five',
53
 
           'one_six',
54
32
           ]
55
33
 
 
34
 
 
35
import warnings
 
36
# Import the 'warn' symbol so bzrlib can call it even if we redefine it
56
37
from warnings import warn
57
38
 
58
39
import bzrlib
59
40
 
60
41
 
61
42
DEPRECATED_PARAMETER = "A deprecated parameter marker."
62
 
zero_seven = "%s was deprecated in version 0.7."
63
 
zero_eight = "%s was deprecated in version 0.8."
64
 
zero_nine = "%s was deprecated in version 0.9."
65
 
zero_ten = "%s was deprecated in version 0.10."
66
 
zero_eleven = "%s was deprecated in version 0.11."
67
 
zero_twelve = "%s was deprecated in version 0.12."
68
 
zero_thirteen = "%s was deprecated in version 0.13."
69
 
zero_fourteen = "%s was deprecated in version 0.14."
70
 
zero_fifteen = "%s was deprecated in version 0.15."
71
 
zero_sixteen = "%s was deprecated in version 0.16."
72
 
zero_seventeen = "%s was deprecated in version 0.17."
73
 
zero_eighteen = "%s was deprecated in version 0.18."
74
 
zero_ninety = "%s was deprecated in version 0.90."
75
 
zero_ninetyone = "%s was deprecated in version 0.91."
76
 
zero_ninetytwo = "%s was deprecated in version 0.92."
77
 
one_zero = "%s was deprecated in version 1.0."
78
 
zero_ninetythree = one_zero # Maintained for backwards compatibility
79
 
one_one = "%s was deprecated in version 1.1."
80
 
one_two = "%s was deprecated in version 1.2."
81
 
one_three = "%s was deprecated in version 1.3."
82
 
one_four = "%s was deprecated in version 1.4."
83
 
one_five = "%s was deprecated in version 1.5."
84
 
one_six = "%s was deprecated in version 1.6."
85
43
 
86
44
 
87
45
def deprecated_in(version_tuple):
88
46
    """Generate a message that something was deprecated in a release.
89
47
 
90
48
    >>> deprecated_in((1, 4, 0))
91
 
    '%s was deprecated in version 1.4.'
 
49
    '%s was deprecated in version 1.4.0.'
92
50
    """
93
51
    return ("%%s was deprecated in version %s."
94
52
            % bzrlib._format_version_tuple(version_tuple))
135
93
 
136
94
    def function_decorator(callable):
137
95
        """This is the function python calls to perform the decoration."""
138
 
        
 
96
 
139
97
        def decorated_function(*args, **kwargs):
140
98
            """This is the decorated function."""
 
99
            from bzrlib import trace
 
100
            trace.mutter_callsite(4, "Deprecated function called")
141
101
            warn(deprecation_string(callable, deprecation_version),
142
102
                DeprecationWarning, stacklevel=2)
143
103
            return callable(*args, **kwargs)
150
110
def deprecated_method(deprecation_version):
151
111
    """Decorate a method so that use of it will trigger a warning.
152
112
 
153
 
    To deprecate a static or class method, use 
 
113
    To deprecate a static or class method, use
154
114
 
155
115
        @staticmethod
156
116
        @deprecated_function
157
117
        def ...
158
 
    
 
118
 
159
119
    To deprecate an entire class, decorate __init__.
160
120
    """
161
121
 
162
122
    def method_decorator(callable):
163
123
        """This is the function python calls to perform the decoration."""
164
 
        
 
124
 
165
125
        def decorated_method(self, *args, **kwargs):
166
126
            """This is the decorated method."""
 
127
            from bzrlib import trace
167
128
            if callable.__name__ == '__init__':
168
129
                symbol = "%s.%s" % (self.__class__.__module__,
169
130
                                    self.__class__.__name__,
173
134
                                       self.__class__.__name__,
174
135
                                       callable.__name__
175
136
                                       )
 
137
            trace.mutter_callsite(4, "Deprecated method called")
176
138
            warn(deprecation_version % symbol, DeprecationWarning, stacklevel=2)
177
139
            return callable(self, *args, **kwargs)
178
140
        _populate_decorated(callable, deprecation_version, "method",
183
145
 
184
146
def deprecated_passed(parameter_value):
185
147
    """Return True if parameter_value was used."""
186
 
    # FIXME: it might be nice to have a parameter deprecation decorator. 
 
148
    # FIXME: it might be nice to have a parameter deprecation decorator.
187
149
    # it would need to handle positional and *args and **kwargs parameters,
188
150
    # which means some mechanism to describe how the parameter was being
189
151
    # passed before deprecation, and some way to deprecate parameters that
209
171
    if len(docstring_lines) == 0:
210
172
        decorated_callable.__doc__ = deprecation_version % ("This " + label)
211
173
    elif len(docstring_lines) == 1:
212
 
        decorated_callable.__doc__ = (callable.__doc__ 
 
174
        decorated_callable.__doc__ = (callable.__doc__
213
175
                                    + "\n"
214
176
                                    + "\n"
215
177
                                    + deprecation_version % ("This " + label)
263
225
            typically from deprecated_in()
264
226
        :param initial_value: The contents of the dict
265
227
        :param variable_name: This allows better warnings to be printed
266
 
        :param advice: String of advice on what callers should do instead 
 
228
        :param advice: String of advice on what callers should do instead
267
229
            of using this variable.
268
230
        """
269
231
        self._deprecation_version = deprecation_version
305
267
        def _warn_deprecated(self, func, *args, **kwargs):
306
268
            warn(msg, DeprecationWarning, stacklevel=3)
307
269
            return func(self, *args, **kwargs)
308
 
            
 
270
 
309
271
        def append(self, obj):
310
272
            """appending to %s is deprecated""" % (variable_name,)
311
273
            return self._warn_deprecated(list.append, obj)
323
285
            return self._warn_deprecated(list.remove, value)
324
286
 
325
287
        def pop(self, index=None):
326
 
            """pop'ing from from %s is deprecated""" % (variable_name,)
 
288
            """pop'ing from %s is deprecated""" % (variable_name,)
327
289
            if index:
328
290
                return self._warn_deprecated(list.pop, index)
329
291
            else:
333
295
    return _DeprecatedList(initial_value)
334
296
 
335
297
 
336
 
def suppress_deprecation_warnings():
 
298
def _check_for_filter(error_only):
 
299
    """Check if there is already a filter for deprecation warnings.
 
300
 
 
301
    :param error_only: Only match an 'error' filter
 
302
    :return: True if a filter is found, False otherwise
 
303
    """
 
304
    for filter in warnings.filters:
 
305
        if issubclass(DeprecationWarning, filter[2]):
 
306
            # This filter will effect DeprecationWarning
 
307
            if not error_only or filter[0] == 'error':
 
308
                return True
 
309
    return False
 
310
 
 
311
 
 
312
def _remove_filter_callable(filter):
 
313
    """Build and returns a callable removing filter from the warnings.
 
314
 
 
315
    :param filter: The filter to remove (can be None).
 
316
 
 
317
    :return: A callable that will remove filter from warnings.filters.
 
318
    """
 
319
    def cleanup():
 
320
        if filter:
 
321
            warnings.filters.remove(filter)
 
322
    return cleanup
 
323
 
 
324
 
 
325
def suppress_deprecation_warnings(override=True):
337
326
    """Call this function to suppress all deprecation warnings.
338
327
 
339
328
    When this is a final release version, we don't want to annoy users with
340
329
    lots of deprecation warnings. We only want the deprecation warnings when
341
330
    running a dev or release candidate.
 
331
 
 
332
    :param override: If True, always set the ignore, if False, only set the
 
333
        ignore if there isn't already a filter.
 
334
 
 
335
    :return: A callable to remove the new warnings this added.
342
336
    """
343
 
    import warnings
344
 
    warnings.filterwarnings('ignore', category=DeprecationWarning)
345
 
 
346
 
 
347
 
def activate_deprecation_warnings():
 
337
    if not override and _check_for_filter(error_only=False):
 
338
        # If there is already a filter effecting suppress_deprecation_warnings,
 
339
        # then skip it.
 
340
        filter = None
 
341
    else:
 
342
        warnings.filterwarnings('ignore', category=DeprecationWarning)
 
343
        filter = warnings.filters[0]
 
344
    return _remove_filter_callable(filter)
 
345
 
 
346
 
 
347
def activate_deprecation_warnings(override=True):
348
348
    """Call this function to activate deprecation warnings.
349
349
 
350
350
    When running in a 'final' release we suppress deprecation warnings.
354
354
    Note: warnings that have already been issued under 'ignore' will not be
355
355
    reported after this point. The 'warnings' module has already marked them as
356
356
    handled, so they don't get issued again.
 
357
 
 
358
    :param override: If False, only add a filter if there isn't an error filter
 
359
        already. (This slightly differs from suppress_deprecation_warnings, in
 
360
        because it always overrides everything but -Werror).
 
361
 
 
362
    :return: A callable to remove the new warnings this added.
357
363
    """
358
 
    import warnings
359
 
    warnings.filterwarnings('default', category=DeprecationWarning)
 
364
    if not override and _check_for_filter(error_only=True):
 
365
        # DeprecationWarnings are already turned into errors, don't downgrade
 
366
        # them to 'default'.
 
367
        filter = None
 
368
    else:
 
369
        warnings.filterwarnings('default', category=DeprecationWarning)
 
370
        filter = warnings.filters[0]
 
371
    return _remove_filter_callable(filter)