~bzr-pqm/bzr/bzr.dev

1185.70.3 by Martin Pool
Various updates to make storage branch mergeable:
1
# Copyright (C) 2005 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
27
2230.2.2 by John Arbash Meinel
Change decorators to define the same parameters as the wrapped func.
28
def _get_parameters(func):
29
    """Recreate the parameters for a function using introspection.
30
2230.2.6 by John Arbash Meinel
Clean up the documentation and imports for decorators (per Martin's suggestions)
31
    :return: (function_params, calling_params)
32
        function_params: is a string representing the parameters of the
33
            function. (such as "a, b, c=None, d=1")
34
            This is used in the function declaration.
35
        calling_params: is another string representing how you would call the
36
            function with the correct parameters. (such as "a, b, c=c, d=d")
37
            Assuming you sued function_params in the function declaration, this
38
            is the parameters to put in the function call.
39
40
        For example:
41
42
        def wrapper(%(function_params)s):
43
            return original(%(calling_params)s)
2230.2.2 by John Arbash Meinel
Change decorators to define the same parameters as the wrapped func.
44
    """
2230.2.6 by John Arbash Meinel
Clean up the documentation and imports for decorators (per Martin's suggestions)
45
    # "import inspect" should stay in local scope. 'inspect' takes a long time
46
    # to import the first time. And since we don't always need it, don't import
47
    # it globally.
48
    import inspect
49
    args, varargs, varkw, defaults = inspect.getargspec(func)
50
    formatted = inspect.formatargspec(args, varargs=varargs,
51
                                      varkw=varkw,
52
                                      defaults=defaults)
2230.2.2 by John Arbash Meinel
Change decorators to define the same parameters as the wrapped func.
53
    if defaults is None:
54
        args_passed = args
55
    else:
56
        first_default = len(args) - len(defaults)
57
        args_passed = args[:first_default]
58
        for arg in args[first_default:]:
59
            args_passed.append("%s=%s" % (arg, arg))
60
    if varargs is not None:
61
        args_passed.append('*' + varargs)
62
    if varkw is not None:
63
        args_passed.append('**' + varkw)
64
    args_passed = ', '.join(args_passed)
65
66
    return formatted[1:-1], args_passed
67
68
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.
69
def _pretty_needs_read_lock(unbound):
1185.70.3 by Martin Pool
Various updates to make storage branch mergeable:
70
    """Decorate unbound to take out and release a read lock.
71
72
    This decorator can be applied to methods of any class with lock_read() and
73
    unlock() methods.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
74
1185.70.3 by Martin Pool
Various updates to make storage branch mergeable:
75
    Typical usage:
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
76
1185.70.3 by Martin Pool
Various updates to make storage branch mergeable:
77
    class Branch(...):
78
        @needs_read_lock
79
        def branch_method(self, ...):
80
            stuff
81
    """
2230.2.2 by John Arbash Meinel
Change decorators to define the same parameters as the wrapped func.
82
    # This compiles a function with a similar name, but wrapped with
83
    # lock_read/unlock calls. We use dynamic creation, because we need the
84
    # internal name of the function to be modified so that --lsprof will see
85
    # the correct name.
86
    # TODO: jam 20070111 Modify this template so that the generated function
87
    #       has the same argument signature as the original function, which
88
    #       will help commands like epydoc.
89
    #       This seems possible by introspecting foo.func_defaults, and
90
    #       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
91
    template = """\
2230.2.2 by John Arbash Meinel
Change decorators to define the same parameters as the wrapped func.
92
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
93
    self.lock_read()
94
    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.
95
        result = unbound(%(passed_params)s)
96
    except:
97
        import sys
98
        exc_info = sys.exc_info()
99
        try:
100
            self.unlock()
101
        finally:
102
            raise exc_info[0], exc_info[1], exc_info[2]
103
    else:
2230.2.1 by John Arbash Meinel
Change the read_lock and write_lock decorators to use custom names
104
        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.
105
        return result
2230.2.1 by John Arbash Meinel
Change the read_lock and write_lock decorators to use custom names
106
read_locked = %(name)s_read_locked
107
"""
2230.2.2 by John Arbash Meinel
Change decorators to define the same parameters as the wrapped func.
108
    params, passed_params = _get_parameters(unbound)
109
    variables = {'name':unbound.__name__,
110
                 'params':params,
111
                 'passed_params':passed_params,
112
                }
113
    func_def = template % variables
114
2230.2.1 by John Arbash Meinel
Change the read_lock and write_lock decorators to use custom names
115
    exec func_def in locals()
116
1534.4.48 by Robert Collins
Make needs_read_lock and needs_write_lock more visible in tracebacks
117
    read_locked.__doc__ = unbound.__doc__
118
    read_locked.__name__ = unbound.__name__
119
    return read_locked
1185.70.3 by Martin Pool
Various updates to make storage branch mergeable:
120
121
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.
122
def _fast_needs_read_lock(unbound):
123
    """Decorate unbound to take out and release a read lock.
124
125
    This decorator can be applied to methods of any class with lock_read() and
126
    unlock() methods.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
127
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.
128
    Typical usage:
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
129
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.
130
    class Branch(...):
131
        @needs_read_lock
132
        def branch_method(self, ...):
133
            stuff
134
    """
135
    def read_locked(self, *args, **kwargs):
136
        self.lock_read()
137
        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.
138
            result = unbound(self, *args, **kwargs)
139
        except:
140
            import sys
141
            exc_info = sys.exc_info()
142
            try:
143
                self.unlock()
144
            finally:
145
                raise exc_info[0], exc_info[1], exc_info[2]
146
        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.
147
            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.
148
            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.
149
    read_locked.__doc__ = unbound.__doc__
150
    read_locked.__name__ = unbound.__name__
151
    return read_locked
152
153
154
def _pretty_needs_write_lock(unbound):
1185.70.3 by Martin Pool
Various updates to make storage branch mergeable:
155
    """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
156
    template = """\
2230.2.2 by John Arbash Meinel
Change decorators to define the same parameters as the wrapped func.
157
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
158
    self.lock_write()
159
    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.
160
        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.
161
    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.
162
        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.
163
        exc_info = sys.exc_info()
164
        try:
165
            self.unlock()
166
        finally:
167
            raise exc_info[0], exc_info[1], exc_info[2]
168
    else:
2230.2.1 by John Arbash Meinel
Change the read_lock and write_lock decorators to use custom names
169
        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.
170
        return result
2230.2.1 by John Arbash Meinel
Change the read_lock and write_lock decorators to use custom names
171
write_locked = %(name)s_write_locked
172
"""
2230.2.2 by John Arbash Meinel
Change decorators to define the same parameters as the wrapped func.
173
    params, passed_params = _get_parameters(unbound)
174
    variables = {'name':unbound.__name__,
175
                 'params':params,
176
                 'passed_params':passed_params,
177
                }
178
    func_def = template % variables
179
2230.2.1 by John Arbash Meinel
Change the read_lock and write_lock decorators to use custom names
180
    exec func_def in locals()
181
1534.4.48 by Robert Collins
Make needs_read_lock and needs_write_lock more visible in tracebacks
182
    write_locked.__doc__ = unbound.__doc__
183
    write_locked.__name__ = unbound.__name__
184
    return write_locked
1185.70.3 by Martin Pool
Various updates to make storage branch mergeable:
185
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.
186
187
def _fast_needs_write_lock(unbound):
188
    """Decorate unbound to take out and release a write lock."""
189
    def write_locked(self, *args, **kwargs):
190
        self.lock_write()
191
        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.
192
            result = unbound(self, *args, **kwargs)
193
        except:
194
            exc_info = sys.exc_info()
195
            try:
196
                self.unlock()
197
            finally:
198
                raise exc_info[0], exc_info[1], exc_info[2]
199
        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.
200
            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.
201
            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.
202
    write_locked.__doc__ = unbound.__doc__
203
    write_locked.__name__ = unbound.__name__
204
    return write_locked
205
206
207
# Default is more functionality, 'bzr' the commandline will request fast
208
# versions.
209
needs_read_lock = _pretty_needs_read_lock
210
needs_write_lock = _pretty_needs_write_lock
211
212
213
def use_fast_decorators():
214
    """Change the default decorators to be fast loading ones.
215
216
    The alternative is to have decorators that do more work to produce
217
    nice-looking decorated functions, but this slows startup time.
218
    """
219
    global needs_read_lock, needs_write_lock
220
    needs_read_lock = _fast_needs_read_lock
221
    needs_write_lock = _fast_needs_write_lock
222
223
224
def use_pretty_decorators():
225
    """Change the default decorators to be pretty ones."""
226
    global needs_read_lock, needs_write_lock
227
    needs_read_lock = _pretty_needs_read_lock
228
    needs_write_lock = _pretty_needs_write_lock