/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/decorators.py

  • Committer: Robert Collins
  • Date: 2008-08-20 02:07:36 UTC
  • mfrom: (3640 +trunk)
  • mto: This revision was merged to the branch mainline in revision 3682.
  • Revision ID: robertc@robertcollins.net-20080820020736-g2xe4921zzxtymle
Merge bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
# Copyright (C) 2005 Canonical Ltd
2
 
 
 
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
5
5
# the Free Software Foundation; either version 2 of the License, or
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
11
# GNU General Public License for more details.
12
 
 
 
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17
17
 
18
18
__all__ = ['needs_read_lock',
19
19
           'needs_write_lock',
 
20
           'use_fast_decorators',
 
21
           'use_pretty_decorators',
20
22
           ]
21
23
 
22
 
def needs_read_lock(unbound):
 
24
 
 
25
import sys
 
26
 
 
27
 
 
28
def _get_parameters(func):
 
29
    """Recreate the parameters for a function using introspection.
 
30
 
 
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)
 
44
    """
 
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)
 
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
 
 
69
def _pretty_needs_read_lock(unbound):
 
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.
 
74
    
 
75
    Typical usage:
 
76
        
 
77
    class Branch(...):
 
78
        @needs_read_lock
 
79
        def branch_method(self, ...):
 
80
            stuff
 
81
    """
 
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
 
91
    template = """\
 
92
def %(name)s_read_locked(%(params)s):
 
93
    self.lock_read()
 
94
    try:
 
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:
 
104
        self.unlock()
 
105
        return result
 
106
read_locked = %(name)s_read_locked
 
107
"""
 
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
 
 
115
    exec func_def in locals()
 
116
 
 
117
    read_locked.__doc__ = unbound.__doc__
 
118
    read_locked.__name__ = unbound.__name__
 
119
    return read_locked
 
120
 
 
121
 
 
122
def _fast_needs_read_lock(unbound):
23
123
    """Decorate unbound to take out and release a read lock.
24
124
 
25
125
    This decorator can be applied to methods of any class with lock_read() and
35
135
    def read_locked(self, *args, **kwargs):
36
136
        self.lock_read()
37
137
        try:
38
 
            return unbound(self, *args, **kwargs)
39
 
        finally:
 
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:
40
147
            self.unlock()
 
148
            return result
41
149
    read_locked.__doc__ = unbound.__doc__
42
150
    read_locked.__name__ = unbound.__name__
43
151
    return read_locked
44
152
 
45
153
 
46
 
def needs_write_lock(unbound):
 
154
def _pretty_needs_write_lock(unbound):
 
155
    """Decorate unbound to take out and release a write lock."""
 
156
    template = """\
 
157
def %(name)s_write_locked(%(params)s):
 
158
    self.lock_write()
 
159
    try:
 
160
        result = unbound(%(passed_params)s)
 
161
    except:
 
162
        import sys
 
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:
 
169
        self.unlock()
 
170
        return result
 
171
write_locked = %(name)s_write_locked
 
172
"""
 
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
 
 
180
    exec func_def in locals()
 
181
 
 
182
    write_locked.__doc__ = unbound.__doc__
 
183
    write_locked.__name__ = unbound.__name__
 
184
    return write_locked
 
185
 
 
186
 
 
187
def _fast_needs_write_lock(unbound):
47
188
    """Decorate unbound to take out and release a write lock."""
48
189
    def write_locked(self, *args, **kwargs):
49
190
        self.lock_write()
50
191
        try:
51
 
            return unbound(self, *args, **kwargs)
52
 
        finally:
 
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:
53
200
            self.unlock()
 
201
            return result
54
202
    write_locked.__doc__ = unbound.__doc__
55
203
    write_locked.__name__ = unbound.__name__
56
204
    return write_locked
57
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