/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: Robert Collins
  • Date: 2006-11-08 00:36:30 UTC
  • mto: This revision was merged to the branch mainline in revision 2124.
  • Revision ID: robertc@robertcollins.net-20061108003630-feb31613c83f7096
(Robert Collins) Extend the problem reporting command line UI to use
apport to report more detailed diagnostics which should help in in getting
faults reported in Malone and provides the basis for capturing more
information such as detailed logging data from the current invocation of
bzr in the future (without cluttering 'bzr.log' unnecessarily).
apport is available from Ubuntu Edgy onwards.

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