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