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