/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/symbol_versioning.py

  • Committer: James Westby
  • Date: 2007-09-18 18:55:00 UTC
  • mto: (2866.1.1 james.westby)
  • mto: This revision was merged to the branch mainline in revision 2867.
  • Revision ID: jw+debian@jameswestby.net-20070918185500-91alkjx8zolds1v8
Fix log against smart server branches that don't support tags. (#140615)

Add get_reverse_tag_dict to DisabledTags for branches that falsely
claim that they support tags (namely smart server branches). When the
remote branch was an old format without tags this caused log to fail.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2006, 2007 Canonical Ltd
 
2
#   Authors: Robert Collins <robert.collins@canonical.com> and others
 
3
#
 
4
# This program is free software; you can redistribute it and/or modify
 
5
# it under the terms of the GNU General Public License as published by
 
6
# the Free Software Foundation; either version 2 of the License, or
 
7
# (at your option) any later version.
 
8
#
 
9
# This program is distributed in the hope that it will be useful,
 
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
# GNU General Public License for more details.
 
13
#
 
14
# You should have received a copy of the GNU General Public License
 
15
# along with this program; if not, write to the Free Software
 
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
17
 
 
18
"""Symbol versioning
 
19
 
 
20
The methods here allow for api symbol versioning.
 
21
"""
 
22
 
 
23
__all__ = ['deprecated_function',
 
24
           'deprecated_list',
 
25
           'deprecated_method',
 
26
           'DEPRECATED_PARAMETER',
 
27
           'deprecated_passed',
 
28
           'warn', 'set_warning_method', 'zero_seven',
 
29
           'zero_eight',
 
30
           'zero_nine',
 
31
           'zero_ten',
 
32
           'zero_eleven',
 
33
           'zero_twelve',
 
34
           'zero_thirteen',
 
35
           'zero_fourteen',
 
36
           'zero_fifteen',
 
37
           'zero_sixteen',
 
38
           'zero_seventeen',
 
39
           'zero_eighteen',
 
40
           'zero_ninety',
 
41
           'zero_ninetyone',
 
42
           ]
 
43
 
 
44
from warnings import warn
 
45
 
 
46
 
 
47
DEPRECATED_PARAMETER = "A deprecated parameter marker."
 
48
zero_seven = "%s was deprecated in version 0.7."
 
49
zero_eight = "%s was deprecated in version 0.8."
 
50
zero_nine = "%s was deprecated in version 0.9."
 
51
zero_ten = "%s was deprecated in version 0.10."
 
52
zero_eleven = "%s was deprecated in version 0.11."
 
53
zero_twelve = "%s was deprecated in version 0.12."
 
54
zero_thirteen = "%s was deprecated in version 0.13."
 
55
zero_fourteen = "%s was deprecated in version 0.14."
 
56
zero_fifteen = "%s was deprecated in version 0.15."
 
57
zero_sixteen = "%s was deprecated in version 0.16."
 
58
zero_seventeen = "%s was deprecated in version 0.17."
 
59
zero_eighteen = "%s was deprecated in version 0.18."
 
60
zero_ninety = "%s was deprecated in version 0.90."
 
61
zero_ninetyone = "%s was deprecated in version 0.91."
 
62
 
 
63
 
 
64
def set_warning_method(method):
 
65
    """Set the warning method to be used by this module.
 
66
 
 
67
    It should take a message and a warning category as warnings.warn does.
 
68
    """
 
69
    global warn
 
70
    warn = method
 
71
 
 
72
 
 
73
# TODO - maybe this would be easier to use as one 'smart' method that
 
74
# guess if it is a method or a class or an attribute ? If so, we can
 
75
# add that on top of the primitives, once we have all three written
 
76
# - RBC 20050105
 
77
 
 
78
 
 
79
def deprecation_string(a_callable, deprecation_version):
 
80
    """Generate an automatic deprecation string for a_callable.
 
81
 
 
82
    :param a_callable: The callable to substitute into deprecation_version.
 
83
    :param deprecation_version: A deprecation format warning string. This should
 
84
        have a single %s operator in it. a_callable will be turned into a nice
 
85
        python symbol and then substituted into deprecation_version.
 
86
    """
 
87
    if getattr(a_callable, 'im_class', None) is None:
 
88
        symbol = "%s.%s" % (a_callable.__module__,
 
89
                            a_callable.__name__)
 
90
    else:
 
91
        symbol = "%s.%s.%s" % (a_callable.im_class.__module__,
 
92
                               a_callable.im_class.__name__,
 
93
                               a_callable.__name__
 
94
                               )
 
95
    return deprecation_version % symbol
 
96
 
 
97
 
 
98
def deprecated_function(deprecation_version):
 
99
    """Decorate a function so that use of it will trigger a warning."""
 
100
 
 
101
    def function_decorator(callable):
 
102
        """This is the function python calls to perform the decoration."""
 
103
        
 
104
        def decorated_function(*args, **kwargs):
 
105
            """This is the decorated function."""
 
106
            warn(deprecation_string(callable, deprecation_version),
 
107
                DeprecationWarning, stacklevel=2)
 
108
            return callable(*args, **kwargs)
 
109
        _populate_decorated(callable, deprecation_version, "function",
 
110
                            decorated_function)
 
111
        return decorated_function
 
112
    return function_decorator
 
113
 
 
114
 
 
115
def deprecated_method(deprecation_version):
 
116
    """Decorate a method so that use of it will trigger a warning.
 
117
 
 
118
    To deprecate a static or class method, use 
 
119
 
 
120
        @staticmethod
 
121
        @deprecated_function
 
122
        def ...
 
123
    
 
124
    To deprecate an entire class, decorate __init__.
 
125
    """
 
126
 
 
127
    def method_decorator(callable):
 
128
        """This is the function python calls to perform the decoration."""
 
129
        
 
130
        def decorated_method(self, *args, **kwargs):
 
131
            """This is the decorated method."""
 
132
            symbol = "%s.%s.%s" % (self.__class__.__module__,
 
133
                                   self.__class__.__name__,
 
134
                                   callable.__name__
 
135
                                   )
 
136
            warn(deprecation_version % symbol, DeprecationWarning, stacklevel=2)
 
137
            return callable(self, *args, **kwargs)
 
138
        _populate_decorated(callable, deprecation_version, "method",
 
139
                            decorated_method)
 
140
        return decorated_method
 
141
    return method_decorator
 
142
 
 
143
 
 
144
def deprecated_passed(parameter_value):
 
145
    """Return True if parameter_value was used."""
 
146
    # FIXME: it might be nice to have a parameter deprecation decorator. 
 
147
    # it would need to handle positional and *args and **kwargs parameters,
 
148
    # which means some mechanism to describe how the parameter was being
 
149
    # passed before deprecation, and some way to deprecate parameters that
 
150
    # were not at the end of the arg list. Thats needed for __init__ where
 
151
    # we cannot just forward to a new method name.I.e. in the following
 
152
    # examples we would want to have callers that pass any value to 'bad' be
 
153
    # given a warning - because we have applied:
 
154
    # @deprecated_parameter('bad', zero_seven)
 
155
    #
 
156
    # def __init__(self, bad=None)
 
157
    # def __init__(self, bad, other)
 
158
    # def __init__(self, **kwargs)
 
159
    # RBC 20060116
 
160
    return not parameter_value is DEPRECATED_PARAMETER
 
161
 
 
162
 
 
163
def _decorate_docstring(callable, deprecation_version, label,
 
164
                        decorated_callable):
 
165
    if callable.__doc__:
 
166
        docstring_lines = callable.__doc__.split('\n')
 
167
    else:
 
168
        docstring_lines = []
 
169
    if len(docstring_lines) == 0:
 
170
        decorated_callable.__doc__ = deprecation_version % ("This " + label)
 
171
    elif len(docstring_lines) == 1:
 
172
        decorated_callable.__doc__ = (callable.__doc__ 
 
173
                                    + "\n"
 
174
                                    + "\n"
 
175
                                    + deprecation_version % ("This " + label)
 
176
                                    + "\n")
 
177
    else:
 
178
        spaces = len(docstring_lines[-1])
 
179
        new_doc = callable.__doc__
 
180
        new_doc += "\n" + " " * spaces
 
181
        new_doc += deprecation_version % ("This " + label)
 
182
        new_doc += "\n" + " " * spaces
 
183
        decorated_callable.__doc__ = new_doc
 
184
 
 
185
 
 
186
def _populate_decorated(callable, deprecation_version, label,
 
187
                        decorated_callable):
 
188
    """Populate attributes like __name__ and __doc__ on the decorated callable.
 
189
    """
 
190
    _decorate_docstring(callable, deprecation_version, label,
 
191
                        decorated_callable)
 
192
    decorated_callable.__module__ = callable.__module__
 
193
    decorated_callable.__name__ = callable.__name__
 
194
    decorated_callable.is_deprecated = True
 
195
 
 
196
 
 
197
def _dict_deprecation_wrapper(wrapped_method):
 
198
    """Returns a closure that emits a warning and calls the superclass"""
 
199
    def cb(dep_dict, *args, **kwargs):
 
200
        msg = 'access to %s' % (dep_dict._variable_name, )
 
201
        msg = dep_dict._deprecation_version % (msg,)
 
202
        if dep_dict._advice:
 
203
            msg += ' ' + dep_dict._advice
 
204
        warn(msg, DeprecationWarning, stacklevel=2)
 
205
        return wrapped_method(dep_dict, *args, **kwargs)
 
206
    return cb
 
207
 
 
208
 
 
209
class DeprecatedDict(dict):
 
210
    """A dictionary that complains when read or written."""
 
211
 
 
212
    is_deprecated = True
 
213
 
 
214
    def __init__(self,
 
215
        deprecation_version,
 
216
        variable_name,
 
217
        initial_value,
 
218
        advice,
 
219
        ):
 
220
        """Create a dict that warns when read or modified.
 
221
 
 
222
        :param deprecation_version: something like zero_nine
 
223
        :param initial_value: The contents of the dict
 
224
        :param variable_name: This allows better warnings to be printed
 
225
        :param advice: String of advice on what callers should do instead 
 
226
            of using this variable.
 
227
        """
 
228
        self._deprecation_version = deprecation_version
 
229
        self._variable_name = variable_name
 
230
        self._advice = advice
 
231
        dict.__init__(self, initial_value)
 
232
 
 
233
    # This isn't every possible method but it should trap anyone using the
 
234
    # dict -- add more if desired
 
235
    __len__ = _dict_deprecation_wrapper(dict.__len__)
 
236
    __getitem__ = _dict_deprecation_wrapper(dict.__getitem__)
 
237
    __setitem__ = _dict_deprecation_wrapper(dict.__setitem__)
 
238
    __delitem__ = _dict_deprecation_wrapper(dict.__delitem__)
 
239
    keys = _dict_deprecation_wrapper(dict.keys)
 
240
    __contains__ = _dict_deprecation_wrapper(dict.__contains__)
 
241
 
 
242
 
 
243
def deprecated_list(deprecation_version, variable_name,
 
244
                    initial_value, extra=None):
 
245
    """Create a list that warns when modified
 
246
 
 
247
    :param deprecation_version: something like zero_nine
 
248
    :param initial_value: The contents of the list
 
249
    :param variable_name: This allows better warnings to be printed
 
250
    :param extra: Extra info to print when printing a warning
 
251
    """
 
252
 
 
253
    subst_text = 'Modifying %s' % (variable_name,)
 
254
    msg = deprecation_version % (subst_text,)
 
255
    if extra:
 
256
        msg += ' ' + extra
 
257
 
 
258
    class _DeprecatedList(list):
 
259
        __doc__ = list.__doc__ + msg
 
260
 
 
261
        is_deprecated = True
 
262
 
 
263
        def _warn_deprecated(self, func, *args, **kwargs):
 
264
            warn(msg, DeprecationWarning, stacklevel=3)
 
265
            return func(self, *args, **kwargs)
 
266
            
 
267
        def append(self, obj):
 
268
            """appending to %s is deprecated""" % (variable_name,)
 
269
            return self._warn_deprecated(list.append, obj)
 
270
 
 
271
        def insert(self, index, obj):
 
272
            """inserting to %s is deprecated""" % (variable_name,)
 
273
            return self._warn_deprecated(list.insert, index, obj)
 
274
 
 
275
        def extend(self, iterable):
 
276
            """extending %s is deprecated""" % (variable_name,)
 
277
            return self._warn_deprecated(list.extend, iterable)
 
278
 
 
279
        def remove(self, value):
 
280
            """removing from %s is deprecated""" % (variable_name,)
 
281
            return self._warn_deprecated(list.remove, value)
 
282
 
 
283
        def pop(self, index=None):
 
284
            """pop'ing from from %s is deprecated""" % (variable_name,)
 
285
            if index:
 
286
                return self._warn_deprecated(list.pop, index)
 
287
            else:
 
288
                # Can't pass None
 
289
                return self._warn_deprecated(list.pop)
 
290
 
 
291
    return _DeprecatedList(initial_value)