~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:
5340.14.2 by John Arbash Meinel
Merge bzr.dev 5916 and make sure the right patch is applied.
112
            try:
113
                raise exc_info[0], exc_info[1], exc_info[2]
114
            finally:
115
                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.
116
    else:
2230.2.1 by John Arbash Meinel
Change the read_lock and write_lock decorators to use custom names
117
        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.
118
        return result
2230.2.1 by John Arbash Meinel
Change the read_lock and write_lock decorators to use custom names
119
read_locked = %(name)s_read_locked
120
"""
5662.1.1 by Andrew Bennetts
Preserve identity of default values in the pretty decorators.
121
    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.
122
    variables = {'name':unbound.__name__,
123
                 'params':params,
124
                 'passed_params':passed_params,
125
                }
126
    func_def = template % variables
127
5662.1.1 by Andrew Bennetts
Preserve identity of default values in the pretty decorators.
128
    scope = dict(defaults_dict)
129
    scope['unbound'] = unbound
130
    exec func_def in scope
131
    read_locked = scope['read_locked']
2230.2.1 by John Arbash Meinel
Change the read_lock and write_lock decorators to use custom names
132
1534.4.48 by Robert Collins
Make needs_read_lock and needs_write_lock more visible in tracebacks
133
    read_locked.__doc__ = unbound.__doc__
134
    read_locked.__name__ = unbound.__name__
135
    return read_locked
1185.70.3 by Martin Pool
Various updates to make storage branch mergeable:
136
137
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.
138
def _fast_needs_read_lock(unbound):
139
    """Decorate unbound to take out and release a read lock.
140
141
    This decorator can be applied to methods of any class with lock_read() and
142
    unlock() methods.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
143
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.
144
    Typical usage:
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
145
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.
146
    class Branch(...):
147
        @needs_read_lock
148
        def branch_method(self, ...):
149
            stuff
150
    """
151
    def read_locked(self, *args, **kwargs):
152
        self.lock_read()
153
        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.
154
            result = unbound(self, *args, **kwargs)
155
        except:
156
            import sys
157
            exc_info = sys.exc_info()
158
            try:
159
                self.unlock()
160
            finally:
5340.14.2 by John Arbash Meinel
Merge bzr.dev 5916 and make sure the right patch is applied.
161
                try:
162
                    raise exc_info[0], exc_info[1], exc_info[2]
163
                finally:
164
                    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.
165
        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.
166
            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.
167
            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.
168
    read_locked.__doc__ = unbound.__doc__
169
    read_locked.__name__ = unbound.__name__
170
    return read_locked
171
172
173
def _pretty_needs_write_lock(unbound):
1185.70.3 by Martin Pool
Various updates to make storage branch mergeable:
174
    """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
175
    template = """\
2230.2.2 by John Arbash Meinel
Change decorators to define the same parameters as the wrapped func.
176
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
177
    self.lock_write()
178
    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.
179
        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.
180
    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.
181
        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.
182
        exc_info = sys.exc_info()
183
        try:
184
            self.unlock()
185
        finally:
5340.14.2 by John Arbash Meinel
Merge bzr.dev 5916 and make sure the right patch is applied.
186
            try:
187
                raise exc_info[0], exc_info[1], exc_info[2]
188
            finally:
189
                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.
190
    else:
2230.2.1 by John Arbash Meinel
Change the read_lock and write_lock decorators to use custom names
191
        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.
192
        return result
2230.2.1 by John Arbash Meinel
Change the read_lock and write_lock decorators to use custom names
193
write_locked = %(name)s_write_locked
194
"""
5662.1.1 by Andrew Bennetts
Preserve identity of default values in the pretty decorators.
195
    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.
196
    variables = {'name':unbound.__name__,
197
                 'params':params,
198
                 'passed_params':passed_params,
199
                }
200
    func_def = template % variables
201
5662.1.1 by Andrew Bennetts
Preserve identity of default values in the pretty decorators.
202
    scope = dict(defaults_dict)
203
    scope['unbound'] = unbound
204
    exec func_def in scope
205
    write_locked = scope['write_locked']
2230.2.1 by John Arbash Meinel
Change the read_lock and write_lock decorators to use custom names
206
1534.4.48 by Robert Collins
Make needs_read_lock and needs_write_lock more visible in tracebacks
207
    write_locked.__doc__ = unbound.__doc__
208
    write_locked.__name__ = unbound.__name__
209
    return write_locked
1185.70.3 by Martin Pool
Various updates to make storage branch mergeable:
210
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.
211
212
def _fast_needs_write_lock(unbound):
213
    """Decorate unbound to take out and release a write lock."""
214
    def write_locked(self, *args, **kwargs):
215
        self.lock_write()
216
        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.
217
            result = unbound(self, *args, **kwargs)
218
        except:
219
            exc_info = sys.exc_info()
220
            try:
221
                self.unlock()
222
            finally:
5340.14.2 by John Arbash Meinel
Merge bzr.dev 5916 and make sure the right patch is applied.
223
                try:
224
                    raise exc_info[0], exc_info[1], exc_info[2]
225
                finally:
226
                    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.
227
        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.
228
            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.
229
            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.
230
    write_locked.__doc__ = unbound.__doc__
231
    write_locked.__name__ = unbound.__name__
232
    return write_locked
233
234
4634.85.9 by Andrew Bennetts
Add some experimental decorators: @only_raises(..) and @cleanup_method.
235
def only_raises(*errors):
4634.62.2 by Andrew Bennetts
Update test_decorators, add docstring.
236
    """Make a decorator that will only allow the given error classes to be
237
    raised.  All other errors will be logged and then discarded.
238
239
    Typical use is something like::
240
241
        @only_raises(LockNotHeld, LockBroken)
242
        def unlock(self):
243
            # etc
244
    """
4634.85.9 by Andrew Bennetts
Add some experimental decorators: @only_raises(..) and @cleanup_method.
245
    def decorator(unbound):
246
        def wrapped(*args, **kwargs):
247
            try:
248
                return unbound(*args, **kwargs)
249
            except errors:
250
                raise
251
            except:
252
                trace.mutter('Error suppressed by only_raises:')
253
                trace.log_exception_quietly()
254
        wrapped.__doc__ = unbound.__doc__
255
        wrapped.__name__ = unbound.__name__
256
        return wrapped
257
    return decorator
258
259
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.
260
# Default is more functionality, 'bzr' the commandline will request fast
261
# versions.
262
needs_read_lock = _pretty_needs_read_lock
263
needs_write_lock = _pretty_needs_write_lock
264
265
266
def use_fast_decorators():
267
    """Change the default decorators to be fast loading ones.
268
269
    The alternative is to have decorators that do more work to produce
270
    nice-looking decorated functions, but this slows startup time.
271
    """
272
    global needs_read_lock, needs_write_lock
273
    needs_read_lock = _fast_needs_read_lock
274
    needs_write_lock = _fast_needs_write_lock
275
276
277
def use_pretty_decorators():
278
    """Change the default decorators to be pretty ones."""
279
    global needs_read_lock, needs_write_lock
280
    needs_read_lock = _pretty_needs_read_lock
281
    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.
282
283
4869.3.32 by Andrew Bennetts
Use Launchpad's cachedproperty decorator instead of my stupidly broken one.
284
# This implementation of cachedproperty is copied from Launchpad's
4869.3.34 by Vincent Ladeuil
Finish the patch based on reviews.
285
# canonical.launchpad.cachedproperty module (with permission from flacoste)
286
# -- spiv & vila 100120
4869.3.32 by Andrew Bennetts
Use Launchpad's cachedproperty decorator instead of my stupidly broken one.
287
def cachedproperty(attrname_or_fn):
288
    """A decorator for methods that makes them properties with their return
289
    value cached.
290
291
    The value is cached on the instance, using the attribute name provided.
292
293
    If you don't provide a name, the mangled name of the property is used.
294
295
    >>> class CachedPropertyTest(object):
296
    ...
297
    ...     @cachedproperty('_foo_cache')
298
    ...     def foo(self):
299
    ...         print 'foo computed'
300
    ...         return 23
301
    ...
302
    ...     @cachedproperty
303
    ...     def bar(self):
304
    ...         print 'bar computed'
305
    ...         return 69
306
307
    >>> cpt = CachedPropertyTest()
308
    >>> getattr(cpt, '_foo_cache', None) is None
309
    True
310
    >>> cpt.foo
311
    foo computed
312
    23
313
    >>> cpt.foo
314
    23
315
    >>> cpt._foo_cache
316
    23
317
    >>> cpt.bar
318
    bar computed
319
    69
320
    >>> cpt._bar_cached_value
321
    69
322
4869.3.13 by Andrew Bennetts
Add simple cachedproperty decorator, and add {this,other,base}_lines cachedproperties to MergeHookParams.
323
    """
4869.3.32 by Andrew Bennetts
Use Launchpad's cachedproperty decorator instead of my stupidly broken one.
324
    if isinstance(attrname_or_fn, basestring):
325
        attrname = attrname_or_fn
326
        return _CachedPropertyForAttr(attrname)
327
    else:
328
        fn = attrname_or_fn
329
        attrname = '_%s_cached_value' % fn.__name__
330
        return _CachedProperty(attrname, fn)
331
332
333
class _CachedPropertyForAttr(object):
334
335
    def __init__(self, attrname):
336
        self.attrname = attrname
337
338
    def __call__(self, fn):
339
        return _CachedProperty(self.attrname, fn)
340
341
342
class _CachedProperty(object):
343
344
    def __init__(self, attrname, fn):
345
        self.fn = fn
346
        self.attrname = attrname
347
        self.marker = object()
348
349
    def __get__(self, inst, cls=None):
350
        if inst is None:
351
            return self
352
        cachedresult = getattr(inst, self.attrname, self.marker)
353
        if cachedresult is self.marker:
354
            result = self.fn(inst)
355
            setattr(inst, self.attrname, result)
356
            return result
357
        else:
358
            return cachedresult