~bzr-pqm/bzr/bzr.dev

4763.2.4 by John Arbash Meinel
merge bzr.2.1 in preparation for NEWS entry.
1
# Copyright (C) 2006-2010 Canonical Ltd
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
2
#
1185.70.3 by Martin Pool
Various updates to make storage branch mergeable:
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
12
#
1185.70.3 by Martin Pool
Various updates to make storage branch mergeable:
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1185.70.3 by Martin Pool
Various updates to make storage branch mergeable:
16
17
1185.65.27 by Robert Collins
Tweak storage towards mergability.
18
__all__ = ['needs_read_lock',
19
           'needs_write_lock',
2230.2.4 by John Arbash Meinel
Add tests that decorators generate useful wrappers.
20
           'use_fast_decorators',
21
           'use_pretty_decorators',
1185.65.27 by Robert Collins
Tweak storage towards mergability.
22
           ]
23
2230.2.2 by John Arbash Meinel
Change decorators to define the same parameters as the wrapped func.
24
3316.3.1 by Andrew Bennetts
Try not to lose the original exception in needs_write_lock decorator if the unlock raises a secondary exception.
25
import sys
26
4634.85.9 by Andrew Bennetts
Add some experimental decorators: @only_raises(..) and @cleanup_method.
27
from bzrlib import trace
28
3316.3.1 by Andrew Bennetts
Try not to lose the original exception in needs_write_lock decorator if the unlock raises a secondary exception.
29
2230.2.2 by John Arbash Meinel
Change decorators to define the same parameters as the wrapped func.
30
def _get_parameters(func):
31
    """Recreate the parameters for a function using introspection.
32
5662.1.1 by Andrew Bennetts
Preserve identity of default values in the pretty decorators.
33
    :return: (function_params, calling_params, default_values)
2230.2.6 by John Arbash Meinel
Clean up the documentation and imports for decorators (per Martin's suggestions)
34
        function_params: is a string representing the parameters of the
35
            function. (such as "a, b, c=None, d=1")
36
            This is used in the function declaration.
37
        calling_params: is another string representing how you would call the
38
            function with the correct parameters. (such as "a, b, c=c, d=d")
5662.1.1 by Andrew Bennetts
Preserve identity of default values in the pretty decorators.
39
            Assuming you used function_params in the function declaration, this
2230.2.6 by John Arbash Meinel
Clean up the documentation and imports for decorators (per Martin's suggestions)
40
            is the parameters to put in the function call.
5662.1.1 by Andrew Bennetts
Preserve identity of default values in the pretty decorators.
41
        default_values_block: a dict with the default values to be passed as
42
            the scope for the 'exec' statement.
2230.2.6 by John Arbash Meinel
Clean up the documentation and imports for decorators (per Martin's suggestions)
43
44
        For example:
45
46
        def wrapper(%(function_params)s):
47
            return original(%(calling_params)s)
2230.2.2 by John Arbash Meinel
Change decorators to define the same parameters as the wrapped func.
48
    """
2230.2.6 by John Arbash Meinel
Clean up the documentation and imports for decorators (per Martin's suggestions)
49
    # "import inspect" should stay in local scope. 'inspect' takes a long time
50
    # to import the first time. And since we don't always need it, don't import
51
    # it globally.
52
    import inspect
53
    args, varargs, varkw, defaults = inspect.getargspec(func)
5662.1.1 by Andrew Bennetts
Preserve identity of default values in the pretty decorators.
54
    defaults_dict = {}
55
    def formatvalue(value):
56
        default_name = '__default_%d' % len(defaults_dict)
57
        defaults_dict[default_name] = value
58
        return '=' + default_name
2230.2.6 by John Arbash Meinel
Clean up the documentation and imports for decorators (per Martin's suggestions)
59
    formatted = inspect.formatargspec(args, varargs=varargs,
60
                                      varkw=varkw,
5662.1.1 by Andrew Bennetts
Preserve identity of default values in the pretty decorators.
61
                                      defaults=defaults,
62
                                      formatvalue=formatvalue)
2230.2.2 by John Arbash Meinel
Change decorators to define the same parameters as the wrapped func.
63
    if defaults is None:
64
        args_passed = args
65
    else:
66
        first_default = len(args) - len(defaults)
67
        args_passed = args[:first_default]
68
        for arg in args[first_default:]:
69
            args_passed.append("%s=%s" % (arg, arg))
70
    if varargs is not None:
71
        args_passed.append('*' + varargs)
72
    if varkw is not None:
73
        args_passed.append('**' + varkw)
74
    args_passed = ', '.join(args_passed)
75
5662.1.1 by Andrew Bennetts
Preserve identity of default values in the pretty decorators.
76
    return formatted[1:-1], args_passed, defaults_dict
2230.2.2 by John Arbash Meinel
Change decorators to define the same parameters as the wrapped func.
77
78
2230.2.3 by John Arbash Meinel
Add the ability to have fast decorators as well as pretty ones, and have 'bzr' select the right one at startup.
79
def _pretty_needs_read_lock(unbound):
1185.70.3 by Martin Pool
Various updates to make storage branch mergeable:
80
    """Decorate unbound to take out and release a read lock.
81
82
    This decorator can be applied to methods of any class with lock_read() and
83
    unlock() methods.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
84
1185.70.3 by Martin Pool
Various updates to make storage branch mergeable:
85
    Typical usage:
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
86
1185.70.3 by Martin Pool
Various updates to make storage branch mergeable:
87
    class Branch(...):
88
        @needs_read_lock
89
        def branch_method(self, ...):
90
            stuff
91
    """
2230.2.2 by John Arbash Meinel
Change decorators to define the same parameters as the wrapped func.
92
    # This compiles a function with a similar name, but wrapped with
93
    # lock_read/unlock calls. We use dynamic creation, because we need the
94
    # internal name of the function to be modified so that --lsprof will see
95
    # the correct name.
96
    # TODO: jam 20070111 Modify this template so that the generated function
97
    #       has the same argument signature as the original function, which
98
    #       will help commands like epydoc.
99
    #       This seems possible by introspecting foo.func_defaults, and
100
    #       foo.func_code.co_argcount and foo.func_code.co_varnames
2230.2.1 by John Arbash Meinel
Change the read_lock and write_lock decorators to use custom names
101
    template = """\
2230.2.2 by John Arbash Meinel
Change decorators to define the same parameters as the wrapped func.
102
def %(name)s_read_locked(%(params)s):
2230.2.1 by John Arbash Meinel
Change the read_lock and write_lock decorators to use custom names
103
    self.lock_read()
104
    try:
3316.3.2 by John Arbash Meinel
Finish fix for bug #125784. need_read/write_lock decorators should attempt to raise an original exception.
105
        result = unbound(%(passed_params)s)
106
    except:
107
        import sys
108
        exc_info = sys.exc_info()
109
        try:
110
            self.unlock()
111
        finally:
112
            raise exc_info[0], exc_info[1], exc_info[2]
113
    else:
2230.2.1 by John Arbash Meinel
Change the read_lock and write_lock decorators to use custom names
114
        self.unlock()
3316.3.2 by John Arbash Meinel
Finish fix for bug #125784. need_read/write_lock decorators should attempt to raise an original exception.
115
        return result
2230.2.1 by John Arbash Meinel
Change the read_lock and write_lock decorators to use custom names
116
read_locked = %(name)s_read_locked
117
"""
5662.1.1 by Andrew Bennetts
Preserve identity of default values in the pretty decorators.
118
    params, passed_params, defaults_dict = _get_parameters(unbound)
2230.2.2 by John Arbash Meinel
Change decorators to define the same parameters as the wrapped func.
119
    variables = {'name':unbound.__name__,
120
                 'params':params,
121
                 'passed_params':passed_params,
122
                }
123
    func_def = template % variables
124
5662.1.1 by Andrew Bennetts
Preserve identity of default values in the pretty decorators.
125
    scope = dict(defaults_dict)
126
    scope['unbound'] = unbound
127
    exec func_def in scope
128
    read_locked = scope['read_locked']
2230.2.1 by John Arbash Meinel
Change the read_lock and write_lock decorators to use custom names
129
1534.4.48 by Robert Collins
Make needs_read_lock and needs_write_lock more visible in tracebacks
130
    read_locked.__doc__ = unbound.__doc__
131
    read_locked.__name__ = unbound.__name__
132
    return read_locked
1185.70.3 by Martin Pool
Various updates to make storage branch mergeable:
133
134
2230.2.3 by John Arbash Meinel
Add the ability to have fast decorators as well as pretty ones, and have 'bzr' select the right one at startup.
135
def _fast_needs_read_lock(unbound):
136
    """Decorate unbound to take out and release a read lock.
137
138
    This decorator can be applied to methods of any class with lock_read() and
139
    unlock() methods.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
140
2230.2.3 by John Arbash Meinel
Add the ability to have fast decorators as well as pretty ones, and have 'bzr' select the right one at startup.
141
    Typical usage:
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
142
2230.2.3 by John Arbash Meinel
Add the ability to have fast decorators as well as pretty ones, and have 'bzr' select the right one at startup.
143
    class Branch(...):
144
        @needs_read_lock
145
        def branch_method(self, ...):
146
            stuff
147
    """
148
    def read_locked(self, *args, **kwargs):
149
        self.lock_read()
150
        try:
3316.3.2 by John Arbash Meinel
Finish fix for bug #125784. need_read/write_lock decorators should attempt to raise an original exception.
151
            result = unbound(self, *args, **kwargs)
152
        except:
153
            import sys
154
            exc_info = sys.exc_info()
155
            try:
156
                self.unlock()
157
            finally:
158
                raise exc_info[0], exc_info[1], exc_info[2]
159
        else:
2230.2.3 by John Arbash Meinel
Add the ability to have fast decorators as well as pretty ones, and have 'bzr' select the right one at startup.
160
            self.unlock()
3316.3.2 by John Arbash Meinel
Finish fix for bug #125784. need_read/write_lock decorators should attempt to raise an original exception.
161
            return result
2230.2.3 by John Arbash Meinel
Add the ability to have fast decorators as well as pretty ones, and have 'bzr' select the right one at startup.
162
    read_locked.__doc__ = unbound.__doc__
163
    read_locked.__name__ = unbound.__name__
164
    return read_locked
165
166
167
def _pretty_needs_write_lock(unbound):
1185.70.3 by Martin Pool
Various updates to make storage branch mergeable:
168
    """Decorate unbound to take out and release a write lock."""
2230.2.1 by John Arbash Meinel
Change the read_lock and write_lock decorators to use custom names
169
    template = """\
2230.2.2 by John Arbash Meinel
Change decorators to define the same parameters as the wrapped func.
170
def %(name)s_write_locked(%(params)s):
2230.2.1 by John Arbash Meinel
Change the read_lock and write_lock decorators to use custom names
171
    self.lock_write()
172
    try:
3316.3.2 by John Arbash Meinel
Finish fix for bug #125784. need_read/write_lock decorators should attempt to raise an original exception.
173
        result = unbound(%(passed_params)s)
3316.3.1 by Andrew Bennetts
Try not to lose the original exception in needs_write_lock decorator if the unlock raises a secondary exception.
174
    except:
3316.3.2 by John Arbash Meinel
Finish fix for bug #125784. need_read/write_lock decorators should attempt to raise an original exception.
175
        import sys
3316.3.1 by Andrew Bennetts
Try not to lose the original exception in needs_write_lock decorator if the unlock raises a secondary exception.
176
        exc_info = sys.exc_info()
177
        try:
178
            self.unlock()
179
        finally:
180
            raise exc_info[0], exc_info[1], exc_info[2]
181
    else:
2230.2.1 by John Arbash Meinel
Change the read_lock and write_lock decorators to use custom names
182
        self.unlock()
3316.3.1 by Andrew Bennetts
Try not to lose the original exception in needs_write_lock decorator if the unlock raises a secondary exception.
183
        return result
2230.2.1 by John Arbash Meinel
Change the read_lock and write_lock decorators to use custom names
184
write_locked = %(name)s_write_locked
185
"""
5662.1.1 by Andrew Bennetts
Preserve identity of default values in the pretty decorators.
186
    params, passed_params, defaults_dict = _get_parameters(unbound)
2230.2.2 by John Arbash Meinel
Change decorators to define the same parameters as the wrapped func.
187
    variables = {'name':unbound.__name__,
188
                 'params':params,
189
                 'passed_params':passed_params,
190
                }
191
    func_def = template % variables
192
5662.1.1 by Andrew Bennetts
Preserve identity of default values in the pretty decorators.
193
    scope = dict(defaults_dict)
194
    scope['unbound'] = unbound
195
    exec func_def in scope
196
    write_locked = scope['write_locked']
2230.2.1 by John Arbash Meinel
Change the read_lock and write_lock decorators to use custom names
197
1534.4.48 by Robert Collins
Make needs_read_lock and needs_write_lock more visible in tracebacks
198
    write_locked.__doc__ = unbound.__doc__
199
    write_locked.__name__ = unbound.__name__
200
    return write_locked
1185.70.3 by Martin Pool
Various updates to make storage branch mergeable:
201
2230.2.3 by John Arbash Meinel
Add the ability to have fast decorators as well as pretty ones, and have 'bzr' select the right one at startup.
202
203
def _fast_needs_write_lock(unbound):
204
    """Decorate unbound to take out and release a write lock."""
205
    def write_locked(self, *args, **kwargs):
206
        self.lock_write()
207
        try:
3316.3.1 by Andrew Bennetts
Try not to lose the original exception in needs_write_lock decorator if the unlock raises a secondary exception.
208
            result = unbound(self, *args, **kwargs)
209
        except:
210
            exc_info = sys.exc_info()
211
            try:
212
                self.unlock()
213
            finally:
214
                raise exc_info[0], exc_info[1], exc_info[2]
215
        else:
2230.2.3 by John Arbash Meinel
Add the ability to have fast decorators as well as pretty ones, and have 'bzr' select the right one at startup.
216
            self.unlock()
3316.3.1 by Andrew Bennetts
Try not to lose the original exception in needs_write_lock decorator if the unlock raises a secondary exception.
217
            return result
2230.2.3 by John Arbash Meinel
Add the ability to have fast decorators as well as pretty ones, and have 'bzr' select the right one at startup.
218
    write_locked.__doc__ = unbound.__doc__
219
    write_locked.__name__ = unbound.__name__
220
    return write_locked
221
222
4634.85.9 by Andrew Bennetts
Add some experimental decorators: @only_raises(..) and @cleanup_method.
223
def only_raises(*errors):
4634.62.2 by Andrew Bennetts
Update test_decorators, add docstring.
224
    """Make a decorator that will only allow the given error classes to be
225
    raised.  All other errors will be logged and then discarded.
226
227
    Typical use is something like::
228
229
        @only_raises(LockNotHeld, LockBroken)
230
        def unlock(self):
231
            # etc
232
    """
4634.85.9 by Andrew Bennetts
Add some experimental decorators: @only_raises(..) and @cleanup_method.
233
    def decorator(unbound):
234
        def wrapped(*args, **kwargs):
235
            try:
236
                return unbound(*args, **kwargs)
237
            except errors:
238
                raise
239
            except:
240
                trace.mutter('Error suppressed by only_raises:')
241
                trace.log_exception_quietly()
242
        wrapped.__doc__ = unbound.__doc__
243
        wrapped.__name__ = unbound.__name__
244
        return wrapped
245
    return decorator
246
247
2230.2.3 by John Arbash Meinel
Add the ability to have fast decorators as well as pretty ones, and have 'bzr' select the right one at startup.
248
# Default is more functionality, 'bzr' the commandline will request fast
249
# versions.
250
needs_read_lock = _pretty_needs_read_lock
251
needs_write_lock = _pretty_needs_write_lock
252
253
254
def use_fast_decorators():
255
    """Change the default decorators to be fast loading ones.
256
257
    The alternative is to have decorators that do more work to produce
258
    nice-looking decorated functions, but this slows startup time.
259
    """
260
    global needs_read_lock, needs_write_lock
261
    needs_read_lock = _fast_needs_read_lock
262
    needs_write_lock = _fast_needs_write_lock
263
264
265
def use_pretty_decorators():
266
    """Change the default decorators to be pretty ones."""
267
    global needs_read_lock, needs_write_lock
268
    needs_read_lock = _pretty_needs_read_lock
269
    needs_write_lock = _pretty_needs_write_lock
4869.3.13 by Andrew Bennetts
Add simple cachedproperty decorator, and add {this,other,base}_lines cachedproperties to MergeHookParams.
270
271
4869.3.32 by Andrew Bennetts
Use Launchpad's cachedproperty decorator instead of my stupidly broken one.
272
# This implementation of cachedproperty is copied from Launchpad's
4869.3.34 by Vincent Ladeuil
Finish the patch based on reviews.
273
# canonical.launchpad.cachedproperty module (with permission from flacoste)
274
# -- spiv & vila 100120
4869.3.32 by Andrew Bennetts
Use Launchpad's cachedproperty decorator instead of my stupidly broken one.
275
def cachedproperty(attrname_or_fn):
276
    """A decorator for methods that makes them properties with their return
277
    value cached.
278
279
    The value is cached on the instance, using the attribute name provided.
280
281
    If you don't provide a name, the mangled name of the property is used.
282
283
    >>> class CachedPropertyTest(object):
284
    ...
285
    ...     @cachedproperty('_foo_cache')
286
    ...     def foo(self):
287
    ...         print 'foo computed'
288
    ...         return 23
289
    ...
290
    ...     @cachedproperty
291
    ...     def bar(self):
292
    ...         print 'bar computed'
293
    ...         return 69
294
295
    >>> cpt = CachedPropertyTest()
296
    >>> getattr(cpt, '_foo_cache', None) is None
297
    True
298
    >>> cpt.foo
299
    foo computed
300
    23
301
    >>> cpt.foo
302
    23
303
    >>> cpt._foo_cache
304
    23
305
    >>> cpt.bar
306
    bar computed
307
    69
308
    >>> cpt._bar_cached_value
309
    69
310
4869.3.13 by Andrew Bennetts
Add simple cachedproperty decorator, and add {this,other,base}_lines cachedproperties to MergeHookParams.
311
    """
4869.3.32 by Andrew Bennetts
Use Launchpad's cachedproperty decorator instead of my stupidly broken one.
312
    if isinstance(attrname_or_fn, basestring):
313
        attrname = attrname_or_fn
314
        return _CachedPropertyForAttr(attrname)
315
    else:
316
        fn = attrname_or_fn
317
        attrname = '_%s_cached_value' % fn.__name__
318
        return _CachedProperty(attrname, fn)
319
320
321
class _CachedPropertyForAttr(object):
322
323
    def __init__(self, attrname):
324
        self.attrname = attrname
325
326
    def __call__(self, fn):
327
        return _CachedProperty(self.attrname, fn)
328
329
330
class _CachedProperty(object):
331
332
    def __init__(self, attrname, fn):
333
        self.fn = fn
334
        self.attrname = attrname
335
        self.marker = object()
336
337
    def __get__(self, inst, cls=None):
338
        if inst is None:
339
            return self
340
        cachedresult = getattr(inst, self.attrname, self.marker)
341
        if cachedresult is self.marker:
342
            result = self.fn(inst)
343
            setattr(inst, self.attrname, result)
344
            return result
345
        else:
346
            return cachedresult