/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: wang
  • Date: 2006-10-29 13:41:32 UTC
  • mto: (2104.4.1 wang_65714)
  • mto: This revision was merged to the branch mainline in revision 2109.
  • Revision ID: wang@ubuntu-20061029134132-3d7f4216f20c4aef
Replace python's difflib by patiencediff because the worst case 
performance is cubic for difflib and people commiting large data 
files are often hurt by this. The worst case performance of patience is 
quadratic. Fix bug 65714.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2006 Canonical Ltd
 
2
#   Authors: Robert Collins <robert.collins@canonical.com>
 
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
           ]
 
35
 
 
36
from warnings import warn
 
37
 
 
38
 
 
39
DEPRECATED_PARAMETER = "A deprecated parameter marker."
 
40
zero_seven = "%s was deprecated in version 0.7."
 
41
zero_eight = "%s was deprecated in version 0.8."
 
42
zero_nine = "%s was deprecated in version 0.9."
 
43
zero_ten = "%s was deprecated in version 0.10."
 
44
zero_eleven = "%s was deprecated in version 0.11."
 
45
zero_twelve = "%s was deprecated in version 0.12."
 
46
 
 
47
 
 
48
def set_warning_method(method):
 
49
    """Set the warning method to be used by this module.
 
50
 
 
51
    It should take a message and a warning category as warnings.warn does.
 
52
    """
 
53
    global warn
 
54
    warn = method
 
55
 
 
56
 
 
57
# TODO - maybe this would be easier to use as one 'smart' method that
 
58
# guess if it is a method or a class or an attribute ? If so, we can
 
59
# add that on top of the primitives, once we have all three written
 
60
# - RBC 20050105
 
61
 
 
62
 
 
63
def deprecation_string(a_callable, deprecation_version):
 
64
    """Generate an automatic deprecation string for a_callable.
 
65
 
 
66
    :param a_callable: The callable to substitute into deprecation_version.
 
67
    :param deprecation_version: A deprecation format warning string. This should
 
68
        have a single %s operator in it. a_callable will be turned into a nice
 
69
        python symbol and then substituted into deprecation_version.
 
70
    """
 
71
    if getattr(a_callable, 'im_class', None) is None:
 
72
        symbol = "%s.%s" % (a_callable.__module__,
 
73
                            a_callable.__name__)
 
74
    else:
 
75
        symbol = "%s.%s.%s" % (a_callable.im_class.__module__,
 
76
                               a_callable.im_class.__name__,
 
77
                               a_callable.__name__
 
78
                               )
 
79
    return deprecation_version % symbol
 
80
 
 
81
 
 
82
def deprecated_function(deprecation_version):
 
83
    """Decorate a function so that use of it will trigger a warning."""
 
84
 
 
85
    def function_decorator(callable):
 
86
        """This is the function python calls to perform the decoration."""
 
87
        
 
88
        def decorated_function(*args, **kwargs):
 
89
            """This is the decorated function."""
 
90
            warn(deprecation_string(callable, deprecation_version),
 
91
                DeprecationWarning, stacklevel=2)
 
92
            return callable(*args, **kwargs)
 
93
        _populate_decorated(callable, deprecation_version, "function",
 
94
                            decorated_function)
 
95
        return decorated_function
 
96
    return function_decorator
 
97
 
 
98
 
 
99
def deprecated_method(deprecation_version):
 
100
    """Decorate a method so that use of it will trigger a warning.
 
101
    
 
102
    To deprecate an entire class, decorate __init__.
 
103
    """
 
104
 
 
105
    def method_decorator(callable):
 
106
        """This is the function python calls to perform the decoration."""
 
107
        
 
108
        def decorated_method(self, *args, **kwargs):
 
109
            """This is the decorated method."""
 
110
            symbol = "%s.%s.%s" % (self.__class__.__module__,
 
111
                                   self.__class__.__name__,
 
112
                                   callable.__name__
 
113
                                   )
 
114
            warn(deprecation_version % symbol, DeprecationWarning, stacklevel=2)
 
115
            return callable(self, *args, **kwargs)
 
116
        _populate_decorated(callable, deprecation_version, "method",
 
117
                            decorated_method)
 
118
        return decorated_method
 
119
    return method_decorator
 
120
 
 
121
 
 
122
def deprecated_passed(parameter_value):
 
123
    """Return True if parameter_value was used."""
 
124
    # FIXME: it might be nice to have a parameter deprecation decorator. 
 
125
    # it would need to handle positional and *args and **kwargs parameters,
 
126
    # which means some mechanism to describe how the parameter was being
 
127
    # passed before deprecation, and some way to deprecate parameters that
 
128
    # were not at the end of the arg list. Thats needed for __init__ where
 
129
    # we cannot just forward to a new method name.I.e. in the following
 
130
    # examples we would want to have callers that pass any value to 'bad' be
 
131
    # given a warning - because we have applied:
 
132
    # @deprecated_parameter('bad', zero_seven)
 
133
    #
 
134
    # def __init__(self, bad=None)
 
135
    # def __init__(self, bad, other)
 
136
    # def __init__(self, **kwargs)
 
137
    # RBC 20060116
 
138
    return not parameter_value is DEPRECATED_PARAMETER
 
139
 
 
140
 
 
141
def _decorate_docstring(callable, deprecation_version, label,
 
142
                        decorated_callable):
 
143
    if callable.__doc__:
 
144
        docstring_lines = callable.__doc__.split('\n')
 
145
    else:
 
146
        docstring_lines = []
 
147
    if len(docstring_lines) == 0:
 
148
        decorated_callable.__doc__ = deprecation_version % ("This " + label)
 
149
    elif len(docstring_lines) == 1:
 
150
        decorated_callable.__doc__ = (callable.__doc__ 
 
151
                                    + "\n"
 
152
                                    + "\n"
 
153
                                    + deprecation_version % ("This " + label)
 
154
                                    + "\n")
 
155
    else:
 
156
        spaces = len(docstring_lines[-1])
 
157
        new_doc = callable.__doc__
 
158
        new_doc += "\n" + " " * spaces
 
159
        new_doc += deprecation_version % ("This " + label)
 
160
        new_doc += "\n" + " " * spaces
 
161
        decorated_callable.__doc__ = new_doc
 
162
 
 
163
 
 
164
def _populate_decorated(callable, deprecation_version, label,
 
165
                        decorated_callable):
 
166
    """Populate attributes like __name__ and __doc__ on the decorated callable.
 
167
    """
 
168
    _decorate_docstring(callable, deprecation_version, label,
 
169
                        decorated_callable)
 
170
    decorated_callable.__module__ = callable.__module__
 
171
    decorated_callable.__name__ = callable.__name__
 
172
    decorated_callable.is_deprecated = True
 
173
 
 
174
 
 
175
def deprecated_list(deprecation_version, variable_name,
 
176
                    initial_value, extra=None):
 
177
    """Create a list that warns when modified
 
178
 
 
179
    :param deprecation_version: something like zero_nine
 
180
    :param initial_value: The contents of the list
 
181
    :param variable_name: This allows better warnings to be printed
 
182
    :param extra: Extra info to print when printing a warning
 
183
    """
 
184
 
 
185
    subst_text = 'Modifying %s' % (variable_name,)
 
186
    msg = deprecation_version % (subst_text,)
 
187
    if extra:
 
188
        msg += ' ' + extra
 
189
 
 
190
    class _DeprecatedList(list):
 
191
        __doc__ = list.__doc__ + msg
 
192
 
 
193
        is_deprecated = True
 
194
 
 
195
        def _warn_deprecated(self, func, *args, **kwargs):
 
196
            warn(msg, DeprecationWarning, stacklevel=3)
 
197
            return func(self, *args, **kwargs)
 
198
            
 
199
        def append(self, obj):
 
200
            """appending to %s is deprecated""" % (variable_name,)
 
201
            return self._warn_deprecated(list.append, obj)
 
202
 
 
203
        def insert(self, index, obj):
 
204
            """inserting to %s is deprecated""" % (variable_name,)
 
205
            return self._warn_deprecated(list.insert, index, obj)
 
206
 
 
207
        def extend(self, iterable):
 
208
            """extending %s is deprecated""" % (variable_name,)
 
209
            return self._warn_deprecated(list.extend, iterable)
 
210
 
 
211
        def remove(self, value):
 
212
            """removing from %s is deprecated""" % (variable_name,)
 
213
            return self._warn_deprecated(list.remove, value)
 
214
 
 
215
        def pop(self, index=None):
 
216
            """pop'ing from from %s is deprecated""" % (variable_name,)
 
217
            if index:
 
218
                return self._warn_deprecated(list.pop, index)
 
219
            else:
 
220
                # Can't pass None
 
221
                return self._warn_deprecated(list.pop)
 
222
 
 
223
    return _DeprecatedList(initial_value)