/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: John Arbash Meinel
  • Date: 2006-08-18 22:17:03 UTC
  • mto: This revision was merged to the branch mainline in revision 1989.
  • Revision ID: john@arbash-meinel.com-20060818221703-958786fafe340fd9
2 changes to knits. Delay creating the .knit or .kndx file until we have actually tried to write data. Because of this, we must allow the Knit to create the prefix directories

Show diffs side-by-side

added added

removed removed

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